home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1999 August / SGI Freeware 1999 August.iso / dist / fw_xemacs.idb / usr / freeware / lib / xemacs-20.4 / lisp / custom / cus-edit.el.z / cus-edit.el
Encoding:
Text File  |  1998-05-21  |  103.0 KB  |  3,248 lines

  1. ;;; cus-edit.el --- Tools for customizating Emacs and Lisp packages.
  2. ;;
  3. ;; Copyright (C) 1996, 1997 Free Software Foundation, Inc.
  4. ;;
  5. ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
  6. ;; Maintainer: Hrvoje Niksic <hniksic@srce.hr>
  7. ;; Keywords: help, faces
  8. ;; Version: 1.9960-x
  9. ;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
  10.  
  11. ;; This file is part of XEmacs.
  12.  
  13. ;; XEmacs is free software; you can redistribute it and/or modify
  14. ;; it under the terms of the GNU General Public License as published by
  15. ;; the Free Software Foundation; either version 2, or (at your option)
  16. ;; any later version.
  17.  
  18. ;; XEmacs is distributed in the hope that it will be useful,
  19. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21. ;; GNU General Public License for more details.
  22.  
  23. ;; You should have received a copy of the GNU General Public License
  24. ;; along with XEmacs; see the file COPYING.  If not, write to the
  25. ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  26. ;; Boston, MA 02111-1307, USA.
  27.  
  28. ;;; Commentary:
  29. ;;
  30. ;; This file implements the code to create and edit customize buffers.
  31. ;;
  32. ;; See `custom.el'.
  33.  
  34. ;; No commands should have names starting with `custom-' because
  35. ;; that interferes with completion.  Use `customize-' for commands
  36. ;; that the user will run with M-x, and `Custom-' for interactive commands.
  37.  
  38.  
  39. ;;; Code:
  40.  
  41. (require 'cus-face)
  42. (require 'wid-edit)
  43. (require 'easymenu)
  44.  
  45. (require 'cus-load)
  46. (require 'cus-start)
  47.  
  48. ;; Huh?  This looks dirty!
  49. (put 'custom-define-hook 'custom-type 'hook)
  50. (put 'custom-define-hook 'standard-value '(nil))
  51. (custom-add-to-group 'customize 'custom-define-hook 'custom-variable)
  52.  
  53. ;;; Customization Groups.
  54.  
  55. (defgroup emacs nil
  56.   "Customization of the One True Editor."
  57.   :link '(custom-manual "(XEmacs)Top"))
  58.  
  59. ;; Most of these groups are stolen from `finder.el',
  60. (defgroup editing nil
  61.   "Basic text editing facilities."
  62.   :group 'emacs)
  63.  
  64. (defgroup abbrev nil
  65.   "Abbreviation handling, typing shortcuts, macros."
  66.   :tag "Abbreviations"
  67.   :group 'editing)
  68.  
  69. (defgroup matching nil
  70.   "Various sorts of searching and matching."
  71.   :group 'editing)
  72.  
  73. (defgroup emulations nil
  74.   "Emulations of other editors."
  75.   :group 'editing)
  76.  
  77. (defgroup mouse nil
  78.   "Mouse support."
  79.   :group 'editing)
  80.  
  81. (defgroup outlines nil
  82.   "Support for hierarchical outlining."
  83.   :group 'editing)
  84.  
  85. (defgroup external nil
  86.   "Interfacing to external utilities."
  87.   :group 'emacs)
  88.  
  89. (defgroup bib nil
  90.   "Code related to the `bib' bibliography processor."
  91.   :tag "Bibliography"
  92.   :group 'external)
  93.  
  94. (defgroup processes nil
  95.   "Process, subshell, compilation, and job control support."
  96.   :group 'external
  97.   :group 'development)
  98.  
  99. (defgroup programming nil
  100.   "Support for programming in other languages."
  101.   :group 'emacs)
  102.  
  103. (defgroup languages nil
  104.   "Specialized modes for editing programming languages."
  105.   :group 'programming)
  106.  
  107. (defgroup lisp nil
  108.   "Lisp support, including Emacs Lisp."
  109.   :group 'languages
  110.   :group 'development)
  111.  
  112. (defgroup c nil
  113.   "Support for the C language and related languages."
  114.   :group 'languages)
  115.  
  116. (defgroup tools nil
  117.   "Programming tools."
  118.   :group 'programming)
  119.  
  120. (defgroup oop nil
  121.   "Support for object-oriented programming."
  122.   :group 'programming)
  123.  
  124. (defgroup applications nil
  125.   "Applications written in Emacs."
  126.   :group 'emacs)
  127.  
  128. (defgroup calendar nil
  129.   "Calendar and time management support."
  130.   :group 'applications)
  131.  
  132. (defgroup mail nil
  133.   "Modes for electronic-mail handling."
  134.   :group 'applications)
  135.  
  136. (defgroup news nil
  137.   "Support for netnews reading and posting."
  138.   :group 'applications)
  139.  
  140. (defgroup games nil
  141.   "Games, jokes and amusements."
  142.   :group 'applications)
  143.  
  144. (defgroup development nil
  145.   "Support for further development of Emacs."
  146.   :group 'emacs)
  147.  
  148. (defgroup docs nil
  149.   "Support for Emacs documentation."
  150.   :group 'development)
  151.  
  152. (defgroup extensions nil
  153.   "Emacs Lisp language extensions."
  154.   :group 'development)
  155.  
  156. (defgroup internal nil
  157.   "Code for Emacs internals, build process, defaults."
  158.   :group 'development)
  159.  
  160. (defgroup maint nil
  161.   "Maintenance aids for the Emacs development group."
  162.   :tag "Maintenance"
  163.   :group 'development)
  164.  
  165. (defgroup environment nil
  166.   "Fitting Emacs with its environment."
  167.   :group 'emacs)
  168.  
  169. (defgroup comm nil
  170.   "Communications, networking, remote access to files."
  171.   :tag "Communication"
  172.   :group 'environment)
  173.  
  174. (defgroup hardware nil
  175.   "Support for interfacing with exotic hardware."
  176.   :group 'environment)
  177.  
  178. (defgroup terminals nil
  179.   "Support for terminal types."
  180.   :group 'environment)
  181.  
  182. (defgroup unix nil
  183.   "Front-ends/assistants for, or emulators of, UNIX features."
  184.   :group 'environment)
  185.  
  186. (defgroup vms nil
  187.   "Support code for vms."
  188.   :group 'environment)
  189.  
  190. (defgroup i18n nil
  191.   "Internationalization and alternate character-set support."
  192.   :group 'environment
  193.   :group 'editing)
  194.  
  195. (defgroup x nil
  196.   "The X Window system."
  197.   :group 'environment)
  198.  
  199. (defgroup frames nil
  200.   "Support for Emacs frames and window systems."
  201.   :group 'environment)
  202.  
  203. (defgroup data nil
  204.   "Support editing files of data."
  205.   :group 'emacs)
  206.  
  207. (defgroup files nil
  208.   "Support editing files."
  209.   :group 'emacs)
  210.  
  211. (defgroup wp nil
  212.   "Word processing."
  213.   :group 'emacs)
  214.  
  215. (defgroup tex nil
  216.   "Code related to the TeX formatter."
  217.   :group 'wp)
  218.  
  219. (defgroup faces nil
  220.   "Support for multiple fonts."
  221.   :group 'emacs)
  222.  
  223. (defgroup hypermedia nil
  224.   "Support for links between text or other media types."
  225.   :group 'emacs)
  226.  
  227. (defgroup help nil
  228.   "Support for on-line help systems."
  229.   :group 'emacs)
  230.  
  231. (defgroup local nil
  232.   "Code local to your site."
  233.   :group 'emacs)
  234.  
  235. (defgroup customize '((widgets custom-group))
  236.   "Customization of the Customization support."
  237.   :link '(custom-manual "(custom)Top")
  238.   :link '(url-link :tag "Development Page"
  239.            "http://www.dina.kvl.dk/~abraham/custom/")
  240.   :prefix "custom-"
  241.   :group 'help)
  242.  
  243. (defgroup custom-faces nil
  244.   "Faces used by customize."
  245.   :group 'customize
  246.   :group 'faces)
  247.  
  248. (defgroup custom-browse nil
  249.   "Control customize browser."
  250.   :prefix "custom-"
  251.   :group 'customize)
  252.  
  253. (defgroup custom-buffer nil
  254.   "Control customize buffers."
  255.   :prefix "custom-"
  256.   :group 'customize)
  257.  
  258. (defgroup custom-menu nil
  259.   "Control customize menus."
  260.   :prefix "custom-"
  261.   :group 'customize)
  262.  
  263. (defgroup abbrev-mode nil
  264.   "Word abbreviations mode."
  265.   :group 'abbrev)
  266.  
  267. (defgroup alloc nil
  268.   "Storage allocation and gc for GNU Emacs Lisp interpreter."
  269.   :tag "Storage Allocation"
  270.   :group 'internal)
  271.  
  272. (defgroup undo nil
  273.   "Undoing changes in buffers."
  274.   :group 'editing)
  275.  
  276. (defgroup modeline nil
  277.   "Content of the modeline."
  278.   :group 'environment)
  279.  
  280. (defgroup fill nil
  281.   "Indenting and filling text."
  282.   :group 'editing)
  283.  
  284. (defgroup editing-basics nil
  285.   "Most basic editing facilities."
  286.   :group 'editing)
  287.  
  288. (defgroup display nil
  289.   "How characters are displayed in buffers."
  290.   :group 'environment)
  291.  
  292. (defgroup execute nil
  293.   "Executing external commands."
  294.   :group 'processes)
  295.  
  296. (defgroup installation nil
  297.   "The Emacs installation."
  298.   :group 'environment)
  299.  
  300. (defgroup dired nil
  301.   "Directory editing."
  302.   :group 'environment)
  303.  
  304. (defgroup limits nil
  305.   "Internal Emacs limits."
  306.   :group 'internal)
  307.  
  308. (defgroup debug nil
  309.   "Debugging Emacs itself."
  310.   :group 'development)
  311.  
  312. (defgroup minibuffer nil
  313.   "Controling the behaviour of the minibuffer."
  314.   :group 'environment)
  315.  
  316. (defgroup keyboard nil
  317.   "Input from the keyboard."
  318.   :group 'environment)
  319.  
  320. (defgroup mouse nil
  321.   "Input from the mouse."
  322.   :group 'environment)
  323.  
  324. (defgroup menu nil
  325.   "Input from the menus."
  326.   :group 'environment)
  327.  
  328. (defgroup auto-save nil
  329.   "Preventing accidential loss of data."
  330.   :group 'files)
  331.  
  332. (defgroup processes-basics nil
  333.   "Basic stuff dealing with processes."
  334.   :group 'processes)
  335.  
  336. (defgroup mule nil
  337.   "Mule XEmacs internationalization."
  338.   :group 'i18n)
  339.  
  340. (defgroup windows nil
  341.   "Windows within a frame."
  342.   :group 'environment)
  343.  
  344.  
  345. ;;; Utilities.
  346.  
  347. (defun custom-quote (sexp)
  348.   "Quote SEXP iff it is not self quoting."
  349.   (if (or (memq sexp '(t nil))
  350.       (keywordp sexp)
  351.       (eq (car-safe sexp) 'lambda)
  352.       (stringp sexp)
  353.       (numberp sexp)
  354.       (characterp sexp))
  355.       sexp
  356.     (list 'quote sexp)))
  357.  
  358. (defun custom-split-regexp-maybe (regexp)
  359.   "If REGEXP is a string, split it to a list at `\\|'.
  360. You can get the original back with from the result with:
  361.   (mapconcat 'identity result \"\\|\")
  362.  
  363. IF REGEXP is not a string, return it unchanged."
  364.   (if (stringp regexp)
  365.       (split-string regexp "\\\\|")
  366.     regexp))
  367.  
  368. (defun custom-variable-prompt ()
  369.   ;; Code stolen from `help.el'.
  370.   "Prompt for a variable, defaulting to the variable at point.
  371. Return a list suitable for use in `interactive'."
  372.    (let ((v (variable-at-point))
  373.      (enable-recursive-minibuffers t)
  374.      val)
  375.      (setq val (completing-read
  376.         (if (symbolp v)
  377.             (format "Customize variable: (default %s) " v)
  378.           "Customize variable: ")
  379.         obarray (lambda (symbol)
  380.               (and (boundp symbol)
  381.                    (or (get symbol 'custom-type)
  382.                    (user-variable-p symbol))))))
  383.      (list (if (equal val "")
  384.            (if (symbolp v) v nil)
  385.          (intern val)))))
  386.  
  387. ;; Here we take not only the actual groups, but the loads, too.
  388. (defun custom-group-prompt (prompt)
  389.   "Read group from minibuffer."
  390.   (let ((completion-ignore-case t))
  391.     (list (completing-read
  392.        prompt obarray
  393.        (lambda (symbol)
  394.          (or (get symbol 'custom-group)
  395.          (get symbol 'custom-loads)))
  396.        t))))
  397.  
  398. (defun custom-menu-filter (menu widget)
  399.   "Convert MENU to the form used by `widget-choose'.
  400. MENU should be in the same format as `custom-variable-menu'.
  401. WIDGET is the widget to apply the filter entries of MENU on."
  402.   (let ((result nil)
  403.     current name action filter)
  404.     (while menu
  405.       (setq current (car menu)
  406.         name (nth 0 current)
  407.         action (nth 1 current)
  408.         filter (nth 2 current)
  409.         menu (cdr menu))
  410.       (if (or (null filter) (funcall filter widget))
  411.       (push (cons name action) result)
  412.     (push name result)))
  413.     (nreverse result)))
  414.  
  415.  
  416. ;;; Unlispify.
  417.  
  418. (defvar custom-prefix-list nil
  419.   "List of prefixes that should be ignored by `custom-unlispify'")
  420.  
  421. (defcustom custom-unlispify-menu-entries t
  422.   "Display menu entries as words instead of symbols if non nil."
  423.   :group 'custom-menu
  424.   :type 'boolean)
  425.  
  426. (defcustom custom-unlispify-remove-prefixes t
  427.   "Non-nil means remove group prefixes from option names in buffers and menus."
  428.   :group 'custom-menu
  429.   :type 'boolean)
  430.  
  431. (defun custom-unlispify-menu-entry (symbol &optional no-suffix)
  432.   "Convert symbol into a menu entry."
  433.   (cond ((not custom-unlispify-menu-entries)
  434.      (symbol-name symbol))
  435.     ((get symbol 'custom-tag)
  436.      (if no-suffix
  437.          (get symbol 'custom-tag)
  438.        (concat (get symbol 'custom-tag) "...")))
  439.     (t
  440.      (with-current-buffer (get-buffer-create " *Custom-Work*")
  441.        (erase-buffer)
  442.        (princ symbol (current-buffer))
  443.        (goto-char (point-min))
  444.        (when (and (eq (get symbol 'custom-type) 'boolean)
  445.               (re-search-forward "-p\\'" nil t))
  446.          (replace-match "" t t)
  447.          (goto-char (point-min)))
  448.        (when custom-unlispify-remove-prefixes
  449.          (let ((prefixes custom-prefix-list)
  450.            prefix)
  451.            (while prefixes
  452.          (setq prefix (car prefixes))
  453.          (if (search-forward prefix (+ (point) (length prefix)) t)
  454.              (progn
  455.                (setq prefixes nil)
  456.                (delete-region (point-min) (point)))
  457.            (setq prefixes (cdr prefixes))))))
  458.        (subst-char-in-region (point-min) (point-max) ?- ?\  t)
  459.        (capitalize-region (point-min) (point-max))
  460.        (unless no-suffix
  461.          (goto-char (point-max))
  462.          (insert "..."))
  463.        (buffer-string)))))
  464.  
  465. (defcustom custom-unlispify-tag-names t
  466.   "Display tag names as words instead of symbols if non nil."
  467.   :group 'custom-buffer
  468.   :type 'boolean)
  469.  
  470. (defun custom-unlispify-tag-name (symbol)
  471.   "Convert symbol into a menu entry."
  472.   (let ((custom-unlispify-menu-entries custom-unlispify-tag-names))
  473.     (custom-unlispify-menu-entry symbol t)))
  474.  
  475. (defun custom-prefix-add (symbol prefixes)
  476.   ;; Addd SYMBOL to list of ignored PREFIXES.
  477.   (cons (or (get symbol 'custom-prefix)
  478.         (concat (symbol-name symbol) "-"))
  479.     prefixes))
  480.  
  481.  
  482. ;;; Guess.
  483.  
  484. (defcustom custom-guess-name-alist
  485.   '(("-p\\'" boolean)
  486.     ("-hooks?\\'" hook)
  487.     ("-face\\'" face)
  488.     ("-file\\'" file)
  489.     ("-function\\'" function)
  490.     ("-functions\\'" (repeat function))
  491.     ("-list\\'" (repeat sexp))
  492.     ("-alist\\'" (repeat (cons sexp sexp))))
  493.   "Alist of (MATCH TYPE).
  494.  
  495. MATCH should be a regexp matching the name of a symbol, and TYPE should
  496. be a widget suitable for editing the value of that symbol.  The TYPE
  497. of the first entry where MATCH matches the name of the symbol will be
  498. used.
  499.  
  500. This is used for guessing the type of variables not declared with
  501. customize."
  502.   :type '(repeat (group (regexp :tag "Match") (sexp :tag "Type")))
  503.   :group 'customize)
  504.  
  505. (defcustom custom-guess-doc-alist
  506.   '(("\\`\\*?Non-nil " boolean))
  507.   "Alist of (MATCH TYPE).
  508.  
  509. MATCH should be a regexp matching a documentation string, and TYPE
  510. should be a widget suitable for editing the value of a variable with
  511. that documentation string.  The TYPE of the first entry where MATCH
  512. matches the name of the symbol will be used.
  513.  
  514. This is used for guessing the type of variables not declared with
  515. customize."
  516.   :type '(repeat (group (regexp :tag "Match") (sexp :tag "Type")))
  517.   :group 'customize)
  518.  
  519. (defun custom-guess-type (symbol)
  520.   "Guess a widget suitable for editing the value of SYMBOL.
  521. This is done by matching SYMBOL with `custom-guess-name-alist' and
  522. if that fails, the doc string with `custom-guess-doc-alist'."
  523.   (let ((name (symbol-name symbol))
  524.     (names custom-guess-name-alist)
  525.     current found)
  526.     (while names
  527.       (setq current (car names)
  528.         names (cdr names))
  529.       (when (string-match (nth 0 current) name)
  530.     (setq found (nth 1 current)
  531.           names nil)))
  532.     (unless found
  533.       (let ((doc (documentation-property symbol 'variable-documentation))
  534.         (docs custom-guess-doc-alist))
  535.     (when doc
  536.       (while docs
  537.         (setq current (car docs)
  538.           docs (cdr docs))
  539.         (when (string-match (nth 0 current) doc)
  540.           (setq found (nth 1 current)
  541.             docs nil))))))
  542.     found))
  543.  
  544.  
  545. ;;; Sorting.
  546.  
  547. (defcustom custom-browse-sort-alphabetically nil
  548.   "If non-nil, sort members of each customization group alphabetically."
  549.   :type 'boolean
  550.   :group 'custom-browse)
  551.  
  552. (defcustom custom-browse-order-groups nil
  553.   "If non-nil, order group members within each customization group.
  554. If `first', order groups before non-groups.
  555. If `last', order groups after non-groups."
  556.   :type '(choice (const first)
  557.          (const last)
  558.          (const :tag "none" nil))
  559.   :group 'custom-browse)
  560.  
  561. (defcustom custom-browse-only-groups nil
  562.   "If non-nil, show group members only within each customization group."
  563.   :type 'boolean
  564.   :group 'custom-browse)
  565.  
  566. (defcustom custom-buffer-sort-alphabetically nil
  567.   "If non-nil, sort members of each customization group alphabetically."
  568.   :type 'boolean
  569.   :group 'custom-buffer)
  570.  
  571. (defcustom custom-buffer-order-groups 'last
  572.   "If non-nil, order group members within each customization group.
  573. If `first', order groups before non-groups.
  574. If `last', order groups after non-groups."
  575.   :type '(choice (const first)
  576.          (const last)
  577.          (const :tag "none" nil))
  578.   :group 'custom-buffer)
  579.  
  580. (defcustom custom-menu-sort-alphabetically nil
  581.   "If non-nil, sort members of each customization group alphabetically."
  582.   :type 'boolean
  583.   :group 'custom-menu)
  584.  
  585. (defcustom custom-menu-order-groups 'first
  586.   "If non-nil, order group members within each customization group.
  587. If `first', order groups before non-groups.
  588. If `last', order groups after non-groups."
  589.   :type '(choice (const first)
  590.          (const last)
  591.          (const :tag "none" nil))
  592.   :group 'custom-menu)
  593.  
  594. (defun custom-sort-items (items sort-alphabetically order-groups)
  595.   "Return a sorted copy of ITEMS.
  596. ITEMS should be a `custom-group' property.
  597. If SORT-ALPHABETICALLY non-nil, sort alphabetically.
  598. If ORDER-GROUPS is `first' order groups before non-groups, if `last' order
  599. groups after non-groups, if nil do not order groups at all."
  600.   (sort (copy-sequence items)
  601.    (lambda (a b)
  602.      (let ((typea (nth 1 a)) (typeb (nth 1 b))
  603.        (namea (symbol-name (nth 0 a))) (nameb (symbol-name (nth 0 b))))
  604.        (cond ((not order-groups)
  605.           ;; Since we don't care about A and B order, maybe sort.
  606.           (when sort-alphabetically
  607.         (string-lessp namea nameb)))
  608.          ((eq typea 'custom-group)
  609.           ;; If B is also a group, maybe sort.  Otherwise, order A and B.
  610.           (if (eq typeb 'custom-group)
  611.           (when sort-alphabetically
  612.             (string-lessp namea nameb))
  613.         (eq order-groups 'first)))
  614.          ((eq typeb 'custom-group)
  615.           ;; Since A cannot be a group, order A and B.
  616.           (eq order-groups 'last))
  617.          (sort-alphabetically
  618.           ;; Since A and B cannot be groups, sort.
  619.           (string-lessp namea nameb)))))))
  620.  
  621.  
  622. ;;; Custom Mode Commands.
  623.  
  624. (defvar custom-options nil
  625.   "Customization widgets in the current buffer.")
  626.  
  627. (defun Custom-set ()
  628.   "Set changes in all modified options."
  629.   (interactive)
  630.   (let ((children custom-options))
  631.     (mapc (lambda (child)
  632.         (when (eq (widget-get child :custom-state) 'modified)
  633.           (widget-apply child :custom-set)))
  634.       children)))
  635.  
  636. (defun Custom-save ()
  637.   "Set all modified group members and save them."
  638.   (interactive)
  639.   (let ((children custom-options))
  640.     (mapc (lambda (child)
  641.         (when (memq (widget-get child :custom-state) '(modified set))
  642.           (widget-apply child :custom-save)))
  643.       children))
  644.   (custom-save-all))
  645.  
  646. (defvar custom-reset-menu
  647.   '(("Current" . Custom-reset-current)
  648.     ("Saved" . Custom-reset-saved)
  649.     ("Standard Settings" . Custom-reset-standard))
  650.   "Alist of actions for the `Reset' button.
  651. The key is a string containing the name of the action, the value is a
  652. lisp function taking the widget as an element which will be called
  653. when the action is chosen.")
  654.  
  655. (defun custom-reset (event)
  656.   "Select item from reset menu."
  657.   (let* ((completion-ignore-case t)
  658.      (answer (widget-choose "Reset to"
  659.                 custom-reset-menu
  660.                 event)))
  661.     (if answer
  662.     (funcall answer))))
  663.  
  664. (defun Custom-reset-current (&rest ignore)
  665.   "Reset all modified group members to their current value."
  666.   (interactive)
  667.   (let ((children custom-options))
  668.     (mapc (lambda (child)
  669.         (when (eq (widget-get child :custom-state) 'modified)
  670.           (widget-apply child :custom-reset-current)))
  671.       children)))
  672.  
  673. (defun Custom-reset-saved (&rest ignore)
  674.   "Reset all modified or set group members to their saved value."
  675.   (interactive)
  676.   (let ((children custom-options))
  677.     (mapc (lambda (child)
  678.         (when (eq (widget-get child :custom-state) 'modified)
  679.           (widget-apply child :custom-reset-saved)))
  680.       children)))
  681.  
  682. (defun Custom-reset-standard (&rest ignore)
  683.   "Reset all modified, set, or saved group members to their standard settings."
  684.   (interactive)
  685.   (let ((children custom-options))
  686.     (mapc (lambda (child)
  687.         (when (eq (widget-get child :custom-state) 'modified)
  688.           (widget-apply child :custom-reset-standard)))
  689.       children)))
  690.  
  691.  
  692. ;;; The Customize Commands
  693.  
  694. (defun custom-prompt-variable (prompt-var prompt-val)
  695.   "Prompt for a variable and a value and return them as a list.
  696. PROMPT-VAR is the prompt for the variable, and PROMPT-VAL is the
  697. prompt for the value.  The %s escape in PROMPT-VAL is replaced with
  698. the name of the variable.
  699.  
  700. If the variable has a `variable-interactive' property, that is used as if
  701. it were the arg to `interactive' (which see) to interactively read the value.
  702.  
  703. If the variable has a `custom-type' property, it must be a widget and the
  704. `:prompt-value' property of that widget will be used for reading the value."
  705.   (let* ((var (read-variable prompt-var))
  706.      (minibuffer-help-form '(describe-variable var)))
  707.     (list var
  708.       (let ((prop (get var 'variable-interactive))
  709.         (type (get var 'custom-type))
  710.         (prompt (format prompt-val var)))
  711.         (unless (listp type)
  712.           (setq type (list type)))
  713.         (cond (prop
  714.            ;; Use VAR's `variable-interactive' property
  715.            ;; as an interactive spec for prompting.
  716.            (call-interactively (list 'lambda '(arg)
  717.                          (list 'interactive prop)
  718.                          'arg)))
  719.           (type
  720.            (widget-prompt-value type
  721.                     prompt
  722.                     (if (boundp var)
  723.                         (symbol-value var))
  724.                     (not (boundp var))))
  725.           (t
  726.            (eval-minibuffer prompt)))))))
  727.  
  728. ;;;###autoload
  729. (defun customize-set-value (var val)
  730.   "Set VARIABLE to VALUE.  VALUE is a Lisp object.
  731.  
  732. If VARIABLE has a `variable-interactive' property, that is used as if
  733. it were the arg to `interactive' (which see) to interactively read the value.
  734.  
  735. If VARIABLE has a `custom-type' property, it must be a widget and the
  736. `:prompt-value' property of that widget will be used for reading the value."
  737.   (interactive (custom-prompt-variable "Set variable: "
  738.                        "Set %s to value: "))
  739.  
  740.   (set var val))
  741.  
  742. ;;;###autoload
  743. (defun customize-set-variable (var val)
  744.   "Set the default for VARIABLE to VALUE.  VALUE is a Lisp object.
  745.  
  746. If VARIABLE has a `custom-set' property, that is used for setting
  747. VARIABLE, otherwise `set-default' is used.
  748.  
  749. The `customized-value' property of the VARIABLE will be set to a list
  750. with a quoted VALUE as its sole list member.
  751.  
  752. If VARIABLE has a `variable-interactive' property, that is used as if
  753. it were the arg to `interactive' (which see) to interactively read the value.
  754.  
  755. If VARIABLE has a `custom-type' property, it must be a widget and the
  756. `:prompt-value' property of that widget will be used for reading the value. "
  757.   (interactive (custom-prompt-variable "Set variable: "
  758.                        "Set customized value for %s to: "))
  759.   (funcall (or (get var 'custom-set) 'set-default) var val)
  760.   (put var 'customized-value (list (custom-quote val))))
  761.  
  762. ;;;###autoload
  763. (defun customize-save-variable (var val)
  764.   "Set the default for VARIABLE to VALUE, and save it for future sessions.
  765. If VARIABLE has a `custom-set' property, that is used for setting
  766. VARIABLE, otherwise `set-default' is used.
  767.  
  768. The `customized-value' property of the VARIABLE will be set to a list
  769. with a quoted VALUE as its sole list member.
  770.  
  771. If VARIABLE has a `variable-interactive' property, that is used as if
  772. it were the arg to `interactive' (which see) to interactively read the value.
  773.  
  774. If VARIABLE has a `custom-type' property, it must be a widget and the
  775. `:prompt-value' property of that widget will be used for reading the value. "
  776.   (interactive (custom-prompt-variable "Set and ave variable: "
  777.                        "Set and save value for %s as: "))
  778.   (funcall (or (get var 'custom-set) 'set-default) var val)
  779.   (put var 'saved-value (list (custom-quote val)))
  780.   (custom-save-all))
  781.  
  782. ;;;###autoload
  783. (defun customize (group)
  784.   "Select a customization buffer which you can use to set user options.
  785. User options are structured into \"groups\".
  786. The default group is `Emacs'."
  787.   (interactive (custom-group-prompt
  788.         "Customize group: (default emacs) "))
  789.   (when (stringp group)
  790.     (if (string-equal "" group)
  791.     (setq group 'emacs)
  792.       (setq group (intern group))))
  793.   (let ((name (format "*Customize Group: %s*"
  794.               (custom-unlispify-tag-name group))))
  795.     (if (get-buffer name)
  796.     (switch-to-buffer name)
  797.       (custom-buffer-create (list (list group 'custom-group))
  798.                 name
  799.                 (concat " for group "
  800.                     (custom-unlispify-tag-name group))))))
  801.  
  802. ;;;###autoload
  803. (defalias 'customize-group 'customize)
  804.  
  805. ;;;###autoload
  806. (defun customize-other-window (symbol)
  807.   "Customize SYMBOL, which must be a customization group."
  808.   (interactive (custom-group-prompt
  809.         "Customize group: (default emacs) "))
  810.   (when (stringp symbol)
  811.     (if (string-equal "" symbol)
  812.     (setq symbol 'emacs)
  813.       (setq symbol (intern symbol))))
  814.   (custom-buffer-create-other-window
  815.    (list (list symbol 'custom-group))
  816.    (format "*Customize Group: %s*" (custom-unlispify-tag-name symbol))))
  817.  
  818. ;;;###autoload
  819. (defalias 'customize-group-other-window 'customize-other-window)
  820.  
  821. ;;;###autoload
  822. (defalias 'customize-option 'customize-variable)
  823.  
  824. ;;;###autoload
  825. (defun customize-variable (symbol)
  826.   "Customize SYMBOL, which must be a user option variable."
  827.   (interactive (custom-variable-prompt))
  828.   (custom-buffer-create (list (list symbol 'custom-variable))
  829.             (format "*Customize Variable: %s*"
  830.                 (custom-unlispify-tag-name symbol))))
  831.  
  832. ;;;###autoload
  833. (defalias 'customize-variable-other-window 'customize-option-other-window)
  834.  
  835. ;;;###autoload
  836. (defun customize-option-other-window (symbol)
  837.   "Customize SYMBOL, which must be a user option variable.
  838. Show the buffer in another window, but don't select it."
  839.   (interactive (custom-variable-prompt))
  840.   (custom-buffer-create-other-window
  841.    (list (list symbol 'custom-variable))
  842.    (format "*Customize Option: %s*" (custom-unlispify-tag-name symbol))))
  843.  
  844. ;;;###autoload
  845. (defun customize-face (&optional symbol)
  846.   "Customize SYMBOL, which should be a face name or nil.
  847. If SYMBOL is nil, customize all faces."
  848.   (interactive (list (completing-read "Customize face: (default all) "
  849.                       obarray 'find-face)))
  850.   (if (or (null symbol) (and (stringp symbol) (zerop (length symbol))))
  851.       (custom-buffer-create (custom-sort-items
  852.                  (mapcar (lambda (symbol)
  853.                        (list symbol 'custom-face))
  854.                      (face-list))
  855.                  t nil)
  856.                 "*Customize Faces*")
  857.     (when (stringp symbol)
  858.       (setq symbol (intern symbol)))
  859.     (unless (symbolp symbol)
  860.       (error "Should be a symbol %S" symbol))
  861.     (custom-buffer-create (list (list symbol 'custom-face))
  862.               (format "*Customize Face: %s*"
  863.                   (custom-unlispify-tag-name symbol)))))
  864.  
  865. ;;;###autoload
  866. (defun customize-face-other-window (&optional symbol)
  867.   "Show customization buffer for FACE in other window."
  868.   (interactive (list (completing-read "Customize face: "
  869.                       obarray 'find-face)))
  870.   (if (or (null symbol) (and (stringp symbol) (zerop (length symbol))))
  871.       ()
  872.     (if (stringp symbol)
  873.     (setq symbol (intern symbol)))
  874.     (unless (symbolp symbol)
  875.       (error "Should be a symbol %S" symbol))
  876.     (custom-buffer-create-other-window
  877.      (list (list symbol 'custom-face))
  878.      (format "*Customize Face: %s*" (custom-unlispify-tag-name symbol)))))
  879.  
  880. ;;;###autoload
  881. (defun customize-customized ()
  882.   "Customize all user options set since the last save in this session."
  883.   (interactive)
  884.   (let ((found nil))
  885.     (mapatoms (lambda (symbol)
  886.         (and (get symbol 'customized-face)
  887.              (find-face symbol)
  888.              (push (list symbol 'custom-face) found))
  889.         (and (get symbol 'customized-value)
  890.              (boundp symbol)
  891.              (push (list symbol 'custom-variable) found))))
  892.     (if (not found)
  893.     (error "No customized user options")
  894.       (custom-buffer-create (custom-sort-items found t nil)
  895.                 "*Customize Customized*"))))
  896.  
  897. ;;;###autoload
  898. (defun customize-saved ()
  899.   "Customize all already saved user options."
  900.   (interactive)
  901.   (let ((found nil))
  902.     (mapatoms (lambda (symbol)
  903.         (and (get symbol 'saved-face)
  904.              (find-face symbol)
  905.              (push (list symbol 'custom-face) found))
  906.         (and (get symbol 'saved-value)
  907.              (boundp symbol)
  908.              (push (list symbol 'custom-variable) found))))
  909.     (if (not found )
  910.     (error "No saved user options")
  911.       (custom-buffer-create (custom-sort-items found t nil)
  912.                 "*Customize Saved*"))))
  913.  
  914. ;;;###autoload
  915. (defun customize-apropos (regexp &optional all)
  916.   "Customize all user options matching REGEXP.
  917. If ALL is `options', include only options.
  918. If ALL is `faces', include only faces.
  919. If ALL is `groups', include only groups.
  920. If ALL is t (interactively, with prefix arg), include options which are not
  921. user-settable, as well as faces and groups."
  922.   (interactive "sCustomize regexp: \nP")
  923.   (let ((found nil))
  924.     (mapatoms (lambda (symbol)
  925.         (when (string-match regexp (symbol-name symbol))
  926.           (when (and (not (memq all '(faces options)))
  927.                  (get symbol 'custom-group))
  928.             (push (list symbol 'custom-group) found))
  929.           (when (and (not (memq all '(options groups)))
  930.                  (find-face symbol))
  931.             (push (list symbol 'custom-face) found))
  932.           (when (and (not (memq all '(groups faces)))
  933.                  (boundp symbol)
  934.                  (or (get symbol 'saved-value)
  935.                  (get symbol 'standard-value)
  936.                  (if (memq all '(nil options))
  937.                      (user-variable-p symbol)
  938.                    (get symbol 'variable-documentation))))
  939.             (push (list symbol 'custom-variable) found)))))
  940.     (if (not found)
  941.     (error "No matches")
  942.       (custom-buffer-create (custom-sort-items found t
  943.                            custom-buffer-order-groups)
  944.                 "*Customize Apropos*"))))
  945.  
  946. ;;;###autoload
  947. (defun customize-apropos-options (regexp &optional arg)
  948.   "Customize all user options matching REGEXP.
  949. With prefix arg, include options which are not user-settable."
  950.   (interactive "sCustomize regexp: \nP")
  951.   (customize-apropos regexp (or arg 'options)))
  952.  
  953. ;;;###autoload
  954. (defun customize-apropos-faces (regexp)
  955.   "Customize all user faces matching REGEXP."
  956.   (interactive "sCustomize regexp: \n")
  957.   (customize-apropos regexp 'faces))
  958.  
  959. ;;;###autoload
  960. (defun customize-apropos-groups (regexp)
  961.   "Customize all user groups matching REGEXP."
  962.   (interactive "sCustomize regexp: \n")
  963.   (customize-apropos regexp 'groups))
  964.  
  965.  
  966. ;;; Buffer.
  967.  
  968. (defcustom custom-buffer-style 'links
  969.   "*Control the presentation style for customization buffers.
  970. The value should be a symbol, one of:
  971.  
  972. brackets: groups nest within each other with big horizontal brackets.
  973. links: groups have links to subgroups."
  974.   :type '(radio (const :tag "brackets: Groups nest within each others" brackets)
  975.         (const :tag "links: Group have links to subgroups" links))
  976.   :group 'custom-buffer)
  977.  
  978. (defcustom custom-buffer-done-function 'kill-buffer
  979.   "*Function to be used to remove the buffer when the user is done with it.
  980. Choices include `kill-buffer' (the default) and `bury-buffer'.
  981. The function will be called with one argument, the buffer to remove."
  982.   :type '(radio (function-item kill-buffer)
  983.         (function-item bury-buffer)
  984.         (function :tag "Other" nil))
  985.   :group 'custom-buffer)
  986.  
  987. (defcustom custom-buffer-indent 3
  988.   "Number of spaces to indent nested groups."
  989.   :type 'integer
  990.   :group 'custom-buffer)
  991.  
  992. ;;;###autoload
  993. (defun custom-buffer-create (options &optional name description)
  994.   "Create a buffer containing OPTIONS.
  995. Optional NAME is the name of the buffer.
  996. OPTIONS should be an alist of the form ((SYMBOL WIDGET)...), where
  997. SYMBOL is a customization option, and WIDGET is a widget for editing
  998. that option."
  999.   (unless name (setq name "*Customization*"))
  1000.   (kill-buffer (get-buffer-create name))
  1001.   (switch-to-buffer (get-buffer-create name))
  1002.   (custom-buffer-create-internal options description))
  1003.  
  1004. ;;;###autoload
  1005. (defun custom-buffer-create-other-window (options &optional name description)
  1006.   "Create a buffer containing OPTIONS.
  1007. Optional NAME is the name of the buffer.
  1008. OPTIONS should be an alist of the form ((SYMBOL WIDGET)...), where
  1009. SYMBOL is a customization option, and WIDGET is a widget for editing
  1010. that option."
  1011.   (unless name (setq name "*Customization*"))
  1012.   (kill-buffer (get-buffer-create name))
  1013.   (let ((window (selected-window)))
  1014.     (switch-to-buffer-other-window (get-buffer-create name))
  1015.     (custom-buffer-create-internal options description)
  1016.     (select-window window)))
  1017.  
  1018. (defcustom custom-reset-button-menu t
  1019.   "If non-nil, only show a single reset button in customize buffers.
  1020. This button will have a menu with all three reset operations."
  1021.   :type 'boolean
  1022.   :group 'custom-buffer)
  1023.  
  1024. (defconst custom-skip-messages 5)
  1025.  
  1026. (defun Custom-buffer-done ()
  1027.   "Remove current buffer.
  1028. This works by calling the function specified by
  1029.  `custom-buffer-done-function'."
  1030.   (interactive)
  1031.   (funcall custom-buffer-done-function (current-buffer)))
  1032.  
  1033. (defun custom-buffer-create-internal (options &optional description)
  1034.   (message "Creating customization buffer...")
  1035.   (custom-mode)
  1036.   (widget-insert "This is a customization buffer")
  1037.   (if description
  1038.       (widget-insert description))
  1039.   (widget-insert ".\n\
  1040. Type RET or click button2 on an active field to invoke its action.
  1041. Invoke ")
  1042.   (widget-create 'info-link
  1043.          :tag "Help"
  1044.          :help-echo "Read the online help"
  1045.          "(XEmacs)Easy Customization")
  1046.   (widget-insert " for more information.\n\n")
  1047.   (message "Creating customization buttons...")
  1048.   (widget-insert "Operate on everything in this buffer:\n ")
  1049.   (widget-create 'push-button
  1050.          :tag "Set"
  1051.          :tag-glyph '("set-up" "set-down")
  1052.          :help-echo "\
  1053. Make your editing in this buffer take effect for this session"
  1054.          :action (lambda (widget &optional event)
  1055.                (Custom-set)))
  1056.   (widget-insert " ")
  1057.   (widget-create 'push-button
  1058.          :tag "Save"
  1059.          :tag-glyph '("save-up" "save-down")
  1060.          :help-echo "\
  1061. Make your editing in this buffer take effect for future Emacs sessions"
  1062.          :action (lambda (widget &optional event)
  1063.                (Custom-save)))
  1064.   (if custom-reset-button-menu
  1065.       (progn
  1066.     (widget-insert " ")
  1067.     (widget-create 'push-button
  1068.                :tag "Reset"
  1069.                :tag-glyph '("reset-up" "reset-down")
  1070.                :help-echo "Show a menu with reset operations"
  1071.                :mouse-down-action (lambda (&rest junk) t)
  1072.                :action (lambda (widget &optional event)
  1073.                  (custom-reset event))))
  1074.     (widget-insert " ")
  1075.     (widget-create 'push-button
  1076.            :tag "Reset"
  1077.            :help-echo "\
  1078. Reset all edited text in this buffer to reflect current values"
  1079.            :action 'Custom-reset-current)
  1080.     (widget-insert " ")
  1081.     (widget-create 'push-button
  1082.            :tag "Reset to Saved"
  1083.            :help-echo "\
  1084. Reset all values in this buffer to their saved settings"
  1085.            :action 'Custom-reset-saved)
  1086.     (widget-insert " ")
  1087.     (widget-create 'push-button
  1088.            :tag "Reset to Standard"
  1089.            :help-echo "\
  1090. Reset all values in this buffer to their standard settings"
  1091.            :action 'Custom-reset-standard))
  1092.   (widget-insert "  ")
  1093.   (widget-create 'push-button
  1094.          :tag "Done"
  1095.          :tag-glyph '("done-up" "done-down")
  1096.          :help-echo "Remove the buffer"
  1097.          :action (lambda (widget &optional event)
  1098.                (Custom-buffer-done)))
  1099.   (widget-insert "\n\n")
  1100.   (message "Creating customization items...")
  1101.   (setq custom-options
  1102.     (if (= (length options) 1)
  1103.         (mapcar (lambda (entry)
  1104.               (widget-create (nth 1 entry)
  1105.                      :documentation-shown t
  1106.                      :custom-state 'unknown
  1107.                      :tag (custom-unlispify-tag-name
  1108.                        (nth 0 entry))
  1109.                      :value (nth 0 entry)))
  1110.             options)
  1111.       (let ((count 0)
  1112.         (length (length options)))
  1113.         (mapcar (lambda (entry)
  1114.               (prog2
  1115.               (display-message
  1116.                'progress
  1117.                (format "Creating customization items %2d%%..."
  1118.                    (/ (* 100.0 count) length)))
  1119.               (widget-create (nth 1 entry)
  1120.                      :tag (custom-unlispify-tag-name
  1121.                            (nth 0 entry))
  1122.                      :value (nth 0 entry))
  1123.             (incf count)
  1124.             (unless (eq (preceding-char) ?\n)
  1125.               (widget-insert "\n"))
  1126.             (widget-insert "\n")))
  1127.             options))))
  1128.   (unless (eq (preceding-char) ?\n)
  1129.     (widget-insert "\n"))
  1130.   (display-message 'progress
  1131.            (format
  1132.             "Creating customization items %2d%%...done" 100))
  1133.   (unless (eq custom-buffer-style 'tree)
  1134.     (mapc 'custom-magic-reset custom-options))
  1135.   (message "Creating customization setup...")
  1136.   (widget-setup)
  1137.   (goto-char (point-min))
  1138.   (message "Creating customization buffer...done"))
  1139.  
  1140.  
  1141. ;;; The Tree Browser.
  1142.  
  1143. ;;;###autoload
  1144. (defun customize-browse (&optional group)
  1145.   "Create a tree browser for the customize hierarchy."
  1146.   (interactive)
  1147.   (unless group
  1148.     (setq group 'emacs))
  1149.   (let ((name "*Customize Browser*"))
  1150.     (kill-buffer (get-buffer-create name))
  1151.     (switch-to-buffer (get-buffer-create name)))
  1152.   (custom-mode)
  1153.   (widget-insert "\
  1154. Square brackets show active fields; type RET or click button2
  1155. on an active field to invoke its action.
  1156. Invoke [+] below to expand a group, and [-] to collapse an expanded group.\n")
  1157.   (if custom-browse-only-groups
  1158.       (widget-insert "\
  1159. Invoke the [Group] button below to edit that item in another window.\n\n")
  1160.     (widget-insert "Invoke the ")
  1161.     (widget-create 'item
  1162.            :format "%t"
  1163.            :tag "[Group]"
  1164.            :tag-glyph "folder")
  1165.     (widget-insert ", ")
  1166.     (widget-create 'item
  1167.            :format "%t"
  1168.            :tag "[Face]"
  1169.            :tag-glyph "face")
  1170.     (widget-insert ", and ")
  1171.     (widget-create 'item
  1172.            :format "%t"
  1173.            :tag "[Option]"
  1174.            :tag-glyph "option")
  1175.     (widget-insert " buttons below to edit that
  1176. item in another window.\n\n"))
  1177.   (let ((custom-buffer-style 'tree))
  1178.     (widget-create 'custom-group
  1179.            :custom-last t
  1180.            :custom-state 'unknown
  1181.            :tag (custom-unlispify-tag-name group)
  1182.            :value group))
  1183.   (widget-add-change)
  1184.   (goto-char (point-min)))
  1185.  
  1186. (define-widget 'custom-browse-visibility 'item
  1187.   "Control visibility of of items in the customize tree browser."
  1188.   :format "%[[%t]%]"
  1189.   :action 'custom-browse-visibility-action)
  1190.  
  1191. (defun custom-browse-visibility-action (widget &rest ignore)
  1192.   (let ((custom-buffer-style 'tree))
  1193.     (custom-toggle-parent widget)))
  1194.  
  1195. (define-widget 'custom-browse-group-tag 'push-button
  1196.   "Show parent in other window when activated."
  1197.   :tag "Group"
  1198.   :tag-glyph "folder"
  1199.   :action 'custom-browse-group-tag-action)
  1200.  
  1201. (defun custom-browse-group-tag-action (widget &rest ignore)
  1202.   (let ((parent (widget-get widget :parent)))
  1203.     (customize-group-other-window (widget-value parent))))
  1204.  
  1205. (define-widget 'custom-browse-variable-tag 'push-button
  1206.   "Show parent in other window when activated."
  1207.   :tag "Option"
  1208.   :tag-glyph "option"
  1209.   :action 'custom-browse-variable-tag-action)
  1210.  
  1211. (defun custom-browse-variable-tag-action (widget &rest ignore)
  1212.   (let ((parent (widget-get widget :parent)))
  1213.     (customize-variable-other-window (widget-value parent))))
  1214.  
  1215. (define-widget 'custom-browse-face-tag 'push-button
  1216.   "Show parent in other window when activated."
  1217.   :tag "Face"
  1218.   :tag-glyph "face"
  1219.   :action 'custom-browse-face-tag-action)
  1220.  
  1221. (defun custom-browse-face-tag-action (widget &rest ignore)
  1222.   (let ((parent (widget-get widget :parent)))
  1223.     (customize-face-other-window (widget-value parent))))
  1224.  
  1225. (defconst custom-browse-alist '(("   " "space")
  1226.                 (" | " "vertical")
  1227.                 ("-\\ " "top")
  1228.                 (" |-" "middle")
  1229.                 (" `-" "bottom")))
  1230.  
  1231. (defun custom-browse-insert-prefix (prefix)
  1232.   "Insert PREFIX.  On XEmacs convert it to line graphics."
  1233.   ;; ### Unfinished.
  1234.   (if nil ; (string-match "XEmacs" emacs-version)
  1235.       (progn
  1236.     (insert "*")
  1237.     (while (not (string-equal prefix ""))
  1238.       (let ((entry (substring prefix 0 3)))
  1239.         (setq prefix (substring prefix 3))
  1240.         (let ((overlay (make-overlay (1- (point)) (point) nil t nil))
  1241.           (name (nth 1 (assoc entry custom-browse-alist))))
  1242.           (overlay-put overlay 'end-glyph (widget-glyph-find name entry))
  1243.           (overlay-put overlay 'start-open t)
  1244.           (overlay-put overlay 'end-open t)))))
  1245.     (insert prefix)))
  1246.  
  1247.  
  1248. ;;; Modification of Basic Widgets.
  1249. ;;
  1250. ;; We add extra properties to the basic widgets needed here.  This is
  1251. ;; fine, as long as we are careful to stay within out own namespace.
  1252. ;;
  1253. ;; We want simple widgets to be displayed by default, but complex
  1254. ;; widgets to be hidden.
  1255.  
  1256. (widget-put (get 'item 'widget-type) :custom-show t)
  1257. (widget-put (get 'editable-field 'widget-type)
  1258.         :custom-show (lambda (widget value)
  1259.                (let ((pp (pp-to-string value)))
  1260.                  (cond ((string-match "\n" pp)
  1261.                     nil)
  1262.                    ((> (length pp) 40)
  1263.                     nil)
  1264.                    (t t)))))
  1265. (widget-put (get 'menu-choice 'widget-type) :custom-show t)
  1266.  
  1267. ;;; The `custom-manual' Widget.
  1268.  
  1269. (define-widget 'custom-manual 'info-link
  1270.   "Link to the manual entry for this customization option."
  1271.   :tag "Manual")
  1272.  
  1273. ;;; The `custom-magic' Widget.
  1274.  
  1275. (defgroup custom-magic-faces nil
  1276.   "Faces used by the magic button."
  1277.   :group 'custom-faces
  1278.   :group 'custom-buffer)
  1279.  
  1280. (defface custom-invalid-face '((((class color))
  1281.                 (:foreground "yellow" :background "red"))
  1282.                    (t
  1283.                 (:bold t :italic t :underline t)))
  1284.   "Face used when the customize item is invalid."
  1285.   :group 'custom-magic-faces)
  1286.  
  1287. (defface custom-rogue-face '((((class color))
  1288.                   (:foreground "pink" :background "black"))
  1289.                  (t
  1290.                   (:underline t)))
  1291.   "Face used when the customize item is not defined for customization."
  1292.   :group 'custom-magic-faces)
  1293.  
  1294. (defface custom-modified-face '((((class color))
  1295.                  (:foreground "white" :background "blue"))
  1296.                 (t
  1297.                  (:italic t :bold)))
  1298.   "Face used when the customize item has been modified."
  1299.   :group 'custom-magic-faces)
  1300.  
  1301. (defface custom-set-face '((((class color))
  1302.                 (:foreground "blue" :background "white"))
  1303.                    (t
  1304.                 (:italic t)))
  1305.   "Face used when the customize item has been set."
  1306.   :group 'custom-magic-faces)
  1307.  
  1308. (defface custom-changed-face '((((class color))
  1309.                 (:foreground "white" :background "blue"))
  1310.                    (t
  1311.                 (:italic t)))
  1312.   "Face used when the customize item has been changed."
  1313.   :group 'custom-magic-faces)
  1314.  
  1315. (defface custom-saved-face '((t (:underline t)))
  1316.   "Face used when the customize item has been saved."
  1317.   :group 'custom-magic-faces)
  1318.  
  1319. (defconst custom-magic-alist '((nil "#" underline "\
  1320. uninitialized, you should not see this.")
  1321.                    (unknown "?" italic "\
  1322. unknown, you should not see this.")
  1323.                    (hidden "-" default "\
  1324. hidden, invoke \"Show\" button in the previous line to show." "\
  1325. group now hidden, invoke the above \"Show\" button to show contents.")
  1326.                    (invalid "x" custom-invalid-face "\
  1327. the value displayed for this %c is invalid and cannot be set.")
  1328.                    (modified "*" custom-modified-face "\
  1329. you have edited the value as text, but you have not set the %c." "\
  1330. you have edited something in this group, but not set it.")
  1331.                    (set "+" custom-set-face "\
  1332. you have set this %c, but not saved it for future sessions." "\
  1333. something in this group has been set, but not saved.")
  1334.                    (changed ":" custom-changed-face "\
  1335. this %c has been changed outside the customize buffer." "\
  1336. something in this group has been changed outside customize.")
  1337.                    (saved "!" custom-saved-face "\
  1338. this %c has been set and saved." "\
  1339. something in this group has been set and saved.")
  1340.                    (rogue "@" custom-rogue-face "\
  1341. this %c has not been changed with customize." "\
  1342. something in this group is not prepared for customization.")
  1343.                    (standard " " nil "\
  1344. this %c is unchanged from its standard setting." "\
  1345. visible group members are all at standard settings."))
  1346.   "Alist of customize option states.
  1347. Each entry is of the form (STATE MAGIC FACE ITEM-DESC [ GROUP-DESC ]), where
  1348.  
  1349. STATE is one of the following symbols:
  1350.  
  1351. `nil'
  1352.    For internal use, should never occur.
  1353. `unknown'
  1354.    For internal use, should never occur.
  1355. `hidden'
  1356.    This item is not being displayed.
  1357. `invalid'
  1358.    This item is modified, but has an invalid form.
  1359. `modified'
  1360.    This item is modified, and has a valid form.
  1361. `set'
  1362.    This item has been set but not saved.
  1363. `changed'
  1364.    The current value of this item has been changed temporarily.
  1365. `saved'
  1366.    This item is marked for saving.
  1367. `rogue'
  1368.    This item has no customization information.
  1369. `standard'
  1370.    This item is unchanged from the standard setting.
  1371.  
  1372. MAGIC is a string used to present that state.
  1373.  
  1374. FACE is a face used to present the state.
  1375.  
  1376. ITEM-DESC is a string describing the state for options.
  1377.  
  1378. GROUP-DESC is a string describing the state for groups.  If this is
  1379. left out, ITEM-DESC will be used.
  1380.  
  1381. The string %c in either description will be replaced with the
  1382. category of the item.  These are `group'. `option', and `face'.
  1383.  
  1384. The list should be sorted most significant first.")
  1385.  
  1386. (defcustom custom-magic-show 'long
  1387.   "If non-nil, show textual description of the state.
  1388. If `long', show a full-line description, not just one word."
  1389.   :type '(choice (const :tag "no" nil)
  1390.          (const short)
  1391.          (const long))
  1392.   :group 'custom-buffer)
  1393.  
  1394. (defcustom custom-magic-show-hidden '(option face)
  1395.   "Control whether the State button is shown for hidden items.
  1396. The value should be a list with the custom categories where the State
  1397. button should be visible.  Possible categories are `group', `option',
  1398. and `face'."
  1399.   :type '(set (const group) (const option) (const face))
  1400.   :group 'custom-buffer)
  1401.  
  1402. (defcustom custom-magic-show-button nil
  1403.   "Show a \"magic\" button indicating the state of each customization option."
  1404.   :type 'boolean
  1405.   :group 'custom-buffer)
  1406.  
  1407. (define-widget 'custom-magic 'default
  1408.   "Show and manipulate state for a customization option."
  1409.   :format "%v"
  1410.   :action 'widget-parent-action
  1411.   :notify 'ignore
  1412.   :value-get 'ignore
  1413.   :value-create 'custom-magic-value-create
  1414.   :value-delete 'widget-children-value-delete)
  1415.  
  1416. (defun widget-magic-mouse-down-action (widget &optional event)
  1417.   ;; Non-nil unless hidden.
  1418.   (not (eq (widget-get (widget-get (widget-get widget :parent) :parent)
  1419.                :custom-state)
  1420.        'hidden)))
  1421.  
  1422. (defun custom-magic-value-create (widget)
  1423.   ;; Create compact status report for WIDGET.
  1424.   (let* ((parent (widget-get widget :parent))
  1425.      (state (widget-get parent :custom-state))
  1426.      (hidden (eq state 'hidden))
  1427.      (entry (assq state custom-magic-alist))
  1428.      (magic (nth 1 entry))
  1429.      (face (nth 2 entry))
  1430.      (category (widget-get parent :custom-category))
  1431.      (text (or (and (eq category 'group)
  1432.             (nth 4 entry))
  1433.            (nth 3 entry)))
  1434.      (form (widget-get parent :custom-form))
  1435.      children)
  1436.     (while (string-match "\\`\\(.*\\)%c\\(.*\\)\\'" text)
  1437.       (setq text (concat (match-string 1 text)
  1438.              (symbol-name category)
  1439.              (match-string 2 text))))
  1440.     (when (and custom-magic-show
  1441.            (or (not hidden)
  1442.            (memq category custom-magic-show-hidden)))
  1443.       (insert "   ")
  1444.       (when (and (eq category 'group)
  1445.          (not (and (eq custom-buffer-style 'links)
  1446.                (> (widget-get parent :custom-level) 1))))
  1447.     (insert-char ?\  (* custom-buffer-indent
  1448.                 (widget-get parent :custom-level))))
  1449.       (push (widget-create-child-and-convert
  1450.          widget 'choice-item
  1451.          :help-echo "Change the state of this item"
  1452.          :format (if hidden "%t" "%[%t%]")
  1453.          :button-prefix 'widget-push-button-prefix
  1454.          :button-suffix 'widget-push-button-suffix
  1455.          :mouse-down-action 'widget-magic-mouse-down-action
  1456.          :tag "State"
  1457.          ;;:tag-glyph (or hidden '("state-up" "state-down"))
  1458.          )
  1459.         children)
  1460.       (insert ": ")
  1461.       (let ((start (point)))
  1462.     (if (eq custom-magic-show 'long)
  1463.         (insert text)
  1464.       (insert (symbol-name state)))
  1465.     (cond ((eq form 'lisp)
  1466.            (insert " (lisp)"))
  1467.           ((eq form 'mismatch)
  1468.            (insert " (mismatch)")))
  1469.     (put-text-property start (point) 'face 'custom-state-face))
  1470.       (insert "\n"))
  1471.     (when (and (eq category 'group)
  1472.            (not (and (eq custom-buffer-style 'links)
  1473.              (> (widget-get parent :custom-level) 1))))
  1474.       (insert-char ?\  (* custom-buffer-indent
  1475.               (widget-get parent :custom-level))))
  1476.     (when custom-magic-show-button
  1477.       (when custom-magic-show
  1478.     (let ((indent (widget-get parent :indent)))
  1479.       (when indent
  1480.         (insert-char ?\  indent))))
  1481.       (push (widget-create-child-and-convert
  1482.          widget 'choice-item
  1483.          :mouse-down-action 'widget-magic-mouse-down-action
  1484.          :button-face face
  1485.          :button-prefix ""
  1486.          :button-suffix ""
  1487.          :help-echo "Change the state"
  1488.          :format (if hidden "%t" "%[%t%]")
  1489.          :tag (if (memq form '(lisp mismatch))
  1490.               (concat "(" magic ")")
  1491.             (concat "[" magic "]")))
  1492.         children)
  1493.       (insert " "))
  1494.     (widget-put widget :children children)))
  1495.  
  1496. (defun custom-magic-reset (widget)
  1497.   "Redraw the :custom-magic property of WIDGET."
  1498.   (let ((magic (widget-get widget :custom-magic)))
  1499.     (widget-value-set magic (widget-value magic))))
  1500.  
  1501. ;;; The `custom' Widget.
  1502.  
  1503. (defface custom-button-face '((t (:bold t)))
  1504.   "Face used for buttons in customization buffers."
  1505.   :group 'custom-faces)
  1506.  
  1507. (defface custom-documentation-face nil
  1508.   "Face used for documentation strings in customization buffers."
  1509.   :group 'custom-faces)
  1510.  
  1511. (defface custom-state-face '((((class color)
  1512.                    (background dark))
  1513.                   (:foreground "lime green"))
  1514.                  (((class color)
  1515.                    (background light))
  1516.                   (:foreground "dark green"))
  1517.                  (t nil))
  1518.   "Face used for State descriptions in the customize buffer."
  1519.   :group 'custom-faces)
  1520.  
  1521. (define-widget 'custom 'default
  1522.   "Customize a user option."
  1523.   :format "%v"
  1524.   :convert-widget 'custom-convert-widget
  1525.   :notify 'custom-notify
  1526.   :custom-prefix ""
  1527.   :custom-level 1
  1528.   :custom-state 'hidden
  1529.   :documentation-property 'widget-subclass-responsibility
  1530.   :value-create 'widget-subclass-responsibility
  1531.   :value-delete 'widget-children-value-delete
  1532.   :value-get 'widget-value-value-get
  1533.   :validate 'widget-children-validate
  1534.   :match (lambda (widget value) (symbolp value)))
  1535.  
  1536. (defun custom-convert-widget (widget)
  1537.   ;; Initialize :value and :tag from :args in WIDGET.
  1538.   (let ((args (widget-get widget :args)))
  1539.     (when args
  1540.       (widget-put widget :value (widget-apply widget
  1541.                           :value-to-internal (car args)))
  1542.       (widget-put widget :tag (custom-unlispify-tag-name (car args)))
  1543.       (widget-put widget :args nil)))
  1544.   widget)
  1545.  
  1546. (defun custom-notify (widget &rest args)
  1547.   "Keep track of changes."
  1548.   (let ((state (widget-get widget :custom-state)))
  1549.     (unless (eq state 'modified)
  1550.       (unless (memq state '(nil unknown hidden))
  1551.     (widget-put widget :custom-state 'modified))
  1552.       (custom-magic-reset widget)
  1553.       (apply 'widget-default-notify widget args))))
  1554.  
  1555. (defun custom-redraw (widget)
  1556.   "Redraw WIDGET with current settings."
  1557.   (let ((line (count-lines (point-min) (point)))
  1558.     (column (current-column))
  1559.     (pos (point))
  1560.     (from (marker-position (widget-get widget :from)))
  1561.     (to (marker-position (widget-get widget :to))))
  1562.     (save-excursion
  1563.       (widget-value-set widget (widget-value widget))
  1564.       (custom-redraw-magic widget))
  1565.     (when (and (>= pos from) (<= pos to))
  1566.       (condition-case nil
  1567.       (progn
  1568.         (if (> column 0)
  1569.         (goto-line line)
  1570.           (goto-line (1+ line)))
  1571.         (move-to-column column))
  1572.     (error nil)))))
  1573.  
  1574. (defun custom-redraw-magic (widget)
  1575.   "Redraw WIDGET state with current settings."
  1576.   (while widget
  1577.     (let ((magic (widget-get widget :custom-magic)))
  1578.       (cond (magic
  1579.          (widget-value-set magic (widget-value magic))
  1580.          (when (setq widget (widget-get widget :group))
  1581.            (custom-group-state-update widget)))
  1582.         (t
  1583.          (setq widget nil)))))
  1584.   (widget-setup))
  1585.  
  1586. (defun custom-show (widget value)
  1587.   "Non-nil if WIDGET should be shown with VALUE by default."
  1588.   (let ((show (widget-get widget :custom-show)))
  1589.     (cond ((null show)
  1590.        nil)
  1591.       ((eq t show)
  1592.        t)
  1593.       (t
  1594.        (funcall show widget value)))))
  1595.  
  1596. (defvar custom-load-recursion nil
  1597.   "Hack to avoid recursive dependencies.")
  1598.  
  1599. (defun custom-load-symbol (symbol)
  1600.   "Load all dependencies for SYMBOL."
  1601.   (unless custom-load-recursion
  1602.     (let ((custom-load-recursion t)
  1603.       (loads (get symbol 'custom-loads))
  1604.       load)
  1605.       (while loads
  1606.     (setq load (car loads)
  1607.           loads (cdr loads))
  1608.     (cond ((symbolp load)
  1609.            (condition-case nil
  1610.            (require load)
  1611.          (error nil)))
  1612.           ;; Don't reload a file already loaded.
  1613.           ((and (boundp 'preloaded-file-list)
  1614.             (member load preloaded-file-list)))
  1615.           ((assoc load load-history))
  1616.           ((assoc (locate-library load) load-history))
  1617.           (t
  1618.            (condition-case nil
  1619.            ;; Without this, we would load cus-edit recursively.
  1620.            ;; We are still loading it when we call this,
  1621.            ;; and it is not in load-history yet.
  1622.            (or (equal load "cus-edit")
  1623.                (load-library load))
  1624.          (error nil))))))))
  1625.  
  1626. (defun custom-load-widget (widget)
  1627.   "Load all dependencies for WIDGET."
  1628.   (custom-load-symbol (widget-value widget)))
  1629.  
  1630. (defun custom-unloaded-symbol-p (symbol)
  1631.   "Return non-nil if the dependencies of SYMBOL has not yet been loaded."
  1632.   (let ((found nil)
  1633.     (loads (get symbol 'custom-loads))
  1634.     load)
  1635.     (while loads
  1636.       (setq load (car loads)
  1637.         loads (cdr loads))
  1638.       (cond ((symbolp load)
  1639.          (unless (featurep load)
  1640.            (setq found t)))
  1641.         ((assoc load load-history))
  1642.         ((assoc (locate-library load) load-history)
  1643.          ;; #### WTF???
  1644.          (message nil))
  1645.         (t
  1646.          (setq found t))))
  1647.     found))
  1648.  
  1649. (defun custom-unloaded-widget-p (widget)
  1650.   "Return non-nil if the dependencies of WIDGET has not yet been loaded."
  1651.   (custom-unloaded-symbol-p (widget-value widget)))
  1652.  
  1653. (defun custom-toggle-hide (widget)
  1654.   "Toggle visibility of WIDGET."
  1655.   (custom-load-widget widget)
  1656.   (let ((state (widget-get widget :custom-state)))
  1657.     (cond ((memq state '(invalid modified))
  1658.        (error "There are unset changes"))
  1659.       ((eq state 'hidden)
  1660.        (widget-put widget :custom-state 'unknown))
  1661.       (t
  1662.        (widget-put widget :documentation-shown nil)
  1663.        (widget-put widget :custom-state 'hidden)))
  1664.     (custom-redraw widget)
  1665.     (widget-setup)))
  1666.  
  1667. (defun custom-toggle-parent (widget &rest ignore)
  1668.   "Toggle visibility of parent of WIDGET."
  1669.   (custom-toggle-hide (widget-get widget :parent)))
  1670.  
  1671. (defun custom-add-see-also (widget &optional prefix)
  1672.   "Add `See also ...' to WIDGET if there are any links.
  1673. Insert PREFIX first if non-nil."
  1674.   (let* ((symbol (widget-get widget :value))
  1675.      (links (get symbol 'custom-links))
  1676.      (many (> (length links) 2))
  1677.      (buttons (widget-get widget :buttons))
  1678.      (indent (widget-get widget :indent)))
  1679.     (when links
  1680.       (when indent
  1681.     (insert-char ?\  indent))
  1682.       (when prefix
  1683.     (insert prefix))
  1684.       (insert "See also ")
  1685.       (while links
  1686.     (push (widget-create-child-and-convert widget (car links))
  1687.           buttons)
  1688.     (setq links (cdr links))
  1689.     (cond ((null links)
  1690.            (insert ".\n"))
  1691.           ((null (cdr links))
  1692.            (if many
  1693.            (insert ", and ")
  1694.          (insert " and ")))
  1695.           (t
  1696.            (insert ", "))))
  1697.       (widget-put widget :buttons buttons))))
  1698.  
  1699. (defun custom-add-parent-links (widget &optional initial-string)
  1700.   "Add \"Parent groups: ...\" to WIDGET if the group has parents.
  1701. The value if non-nil if any parents were found.
  1702. If INITIAL-STRING is non-nil, use that rather than \"Parent groups:\"."
  1703.   (let ((name (widget-value widget))
  1704.     (type (widget-type widget))
  1705.     (buttons (widget-get widget :buttons))
  1706.     (start (point))
  1707.     found)
  1708.     (insert (or initial-string "Parent groups:"))
  1709.     (maphash (lambda (group ignore)
  1710.            (let ((entry (assq name (get group 'custom-group))))
  1711.          (when (eq (nth 1 entry) type)
  1712.            (insert " ")
  1713.            (push (widget-create-child-and-convert
  1714.               widget 'custom-group-link
  1715.               :tag (custom-unlispify-tag-name group)
  1716.               group)
  1717.              buttons)
  1718.            (setq found t))))
  1719.          custom-group-hash-table)
  1720.     (widget-put widget :buttons buttons)
  1721.     (if found
  1722.     (insert "\n")
  1723.       (delete-region start (point)))
  1724.     found))
  1725.  
  1726. ;;; The `custom-variable' Widget.
  1727.  
  1728. (defface custom-variable-tag-face '((((class color)
  1729.                       (background dark))
  1730.                      (:foreground "light blue" :underline t))
  1731.                     (((class color)
  1732.                       (background light))
  1733.                      (:foreground "blue" :underline t))
  1734.                     (t (:underline t)))
  1735.   "Face used for unpushable variable tags."
  1736.   :group 'custom-faces)
  1737.  
  1738. (defface custom-variable-button-face '((t (:underline t :bold t)))
  1739.   "Face used for pushable variable tags."
  1740.   :group 'custom-faces)
  1741.  
  1742. (define-widget 'custom-variable 'custom
  1743.   "Customize variable."
  1744.   :format "%v"
  1745.   :help-echo "Set or reset this variable"
  1746.   :documentation-property 'variable-documentation
  1747.   :custom-category 'option
  1748.   :custom-state nil
  1749.   :custom-menu 'custom-variable-menu-create
  1750.   :custom-form 'edit
  1751.   :value-create 'custom-variable-value-create
  1752.   :action 'custom-variable-action
  1753.   :custom-set 'custom-variable-set
  1754.   :custom-save 'custom-variable-save
  1755.   :custom-reset-current 'custom-redraw
  1756.   :custom-reset-saved 'custom-variable-reset-saved
  1757.   :custom-reset-standard 'custom-variable-reset-standard)
  1758.  
  1759. (defun custom-variable-type (symbol)
  1760.   "Return a widget suitable for editing the value of SYMBOL.
  1761. If SYMBOL has a `custom-type' property, use that.
  1762. Otherwise, look up symbol in `custom-guess-type-alist'."
  1763.   (let* ((type (or (get symbol 'custom-type)
  1764.            (and (not (get symbol 'standard-value))
  1765.             (custom-guess-type symbol))
  1766.            'sexp))
  1767.      (options (get symbol 'custom-options))
  1768.      (tmp (if (listp type)
  1769.           (copy-sequence type)
  1770.         (list type))))
  1771.     (when options
  1772.       (widget-put tmp :options options))
  1773.     tmp))
  1774.  
  1775. (defun custom-variable-value-create (widget)
  1776.   "Here is where you edit the variables value."
  1777.   (custom-load-widget widget)
  1778.   (let* ((buttons (widget-get widget :buttons))
  1779.      (children (widget-get widget :children))
  1780.      (form (widget-get widget :custom-form))
  1781.      (state (widget-get widget :custom-state))
  1782.      (symbol (widget-get widget :value))
  1783.      (tag (widget-get widget :tag))
  1784.      (type (custom-variable-type symbol))
  1785.      (conv (widget-convert type))
  1786.      (get (or (get symbol 'custom-get) 'default-value))
  1787.      (prefix (widget-get widget :custom-prefix))
  1788.      (last (widget-get widget :custom-last))
  1789.      (value (if (default-boundp symbol)
  1790.             (funcall get symbol)
  1791.           (widget-get conv :value))))
  1792.     ;; If the widget is new, the child determine whether it is hidden.
  1793.     (cond (state)
  1794.       ((custom-show type value)
  1795.        (setq state 'unknown))
  1796.       (t
  1797.        (setq state 'hidden)))
  1798.     ;; If we don't know the state, see if we need to edit it in lisp form.
  1799.     (when (eq state 'unknown)
  1800.       (unless (widget-apply conv :match value)
  1801.     ;; (widget-apply (widget-convert type) :match value)
  1802.     (setq form 'mismatch)))
  1803.     ;; Now we can create the child widget.
  1804.     (cond ((eq custom-buffer-style 'tree)
  1805.        (insert prefix (if last " `--- " " |--- "))
  1806.        (push (widget-create-child-and-convert
  1807.           widget 'custom-browse-variable-tag)
  1808.          buttons)
  1809.        (insert " " tag "\n")
  1810.        (widget-put widget :buttons buttons))
  1811.       ((eq state 'hidden)
  1812.        ;; Indicate hidden value.
  1813.        (push (widget-create-child-and-convert
  1814.           widget 'item
  1815.           :format "%{%t%}: "
  1816.           :sample-face 'custom-variable-tag-face
  1817.           :tag tag
  1818.           :parent widget)
  1819.          buttons)
  1820.        (push (widget-create-child-and-convert
  1821.           widget 'visibility
  1822.           :help-echo "Show the value of this option"
  1823.           :action 'custom-toggle-parent
  1824.           nil)
  1825.          buttons))
  1826.       ((memq form '(lisp mismatch))
  1827.        ;; In lisp mode edit the saved value when possible.
  1828.        (let* ((value (cond ((get symbol 'saved-value)
  1829.                 (car (get symbol 'saved-value)))
  1830.                    ((get symbol 'standard-value)
  1831.                 (car (get symbol 'standard-value)))
  1832.                    ((default-boundp symbol)
  1833.                 (custom-quote (funcall get symbol)))
  1834.                    (t
  1835.                 (custom-quote (widget-get conv :value))))))
  1836.          (insert (symbol-name symbol) ": ")
  1837.          (push (widget-create-child-and-convert
  1838.             widget 'visibility
  1839.             :help-echo "Hide the value of this option"
  1840.             :action 'custom-toggle-parent
  1841.             t)
  1842.            buttons)
  1843.          (insert " ")
  1844.          (push (widget-create-child-and-convert
  1845.             widget 'sexp
  1846.             :button-face 'custom-variable-button-face
  1847.             :format "%v"
  1848.             :tag (symbol-name symbol)
  1849.             :parent widget
  1850.             :value value)
  1851.            children)))
  1852.       (t
  1853.        ;; Edit mode.
  1854.        (let* ((format (widget-get type :format))
  1855.           tag-format value-format)
  1856.          (unless (string-match ":" format)
  1857.            (error "Bad format."))
  1858.          (setq tag-format (substring format 0 (match-end 0)))
  1859.          (setq value-format (substring format (match-end 0)))
  1860.          (push (widget-create-child-and-convert
  1861.             widget 'item
  1862.             :format tag-format
  1863.             :action 'custom-tag-action
  1864.             :help-echo "Change value of this option"
  1865.             :mouse-down-action 'custom-tag-mouse-down-action
  1866.             :button-face 'custom-variable-button-face
  1867.             :sample-face 'custom-variable-tag-face
  1868.             tag)
  1869.            buttons)
  1870.          (insert " ")
  1871.          (push (widget-create-child-and-convert
  1872.           widget 'visibility
  1873.           :help-echo "Hide the value of this option"
  1874.           :action 'custom-toggle-parent
  1875.           t)
  1876.          buttons)
  1877.          (push (widget-create-child-and-convert
  1878.             widget type
  1879.             :format value-format
  1880.             :value value)
  1881.            children))))
  1882.     (unless (eq custom-buffer-style 'tree)
  1883.       ;; Now update the state.
  1884.       (unless (eq (preceding-char) ?\n)
  1885.     (widget-insert "\n"))
  1886.       (if (eq state 'hidden)
  1887.       (widget-put widget :custom-state state)
  1888.     (custom-variable-state-set widget))
  1889.       ;; Create the magic button.
  1890.       (let ((magic (widget-create-child-and-convert
  1891.             widget 'custom-magic nil)))
  1892.     (widget-put widget :custom-magic magic)
  1893.     (push magic buttons))
  1894.       ;; Update properties.
  1895.       (widget-put widget :custom-form form)
  1896.       (widget-put widget :buttons buttons)
  1897.       (widget-put widget :children children)
  1898.       ;; Insert documentation.
  1899.       (widget-default-format-handler widget ?h)
  1900.       ;; See also.
  1901.       (unless (eq state 'hidden)
  1902.     (when (eq (widget-get widget :custom-level) 1)
  1903.       (custom-add-parent-links widget))
  1904.     (custom-add-see-also widget)))))
  1905.  
  1906. (defun custom-tag-action (widget &rest args)
  1907.   "Pass :action to first child of WIDGET's parent."
  1908.   (apply 'widget-apply (car (widget-get (widget-get widget :parent) :children))
  1909.      :action args))
  1910.  
  1911. (defun custom-tag-mouse-down-action (widget &rest args)
  1912.   "Pass :mouse-down-action to first child of WIDGET's parent."
  1913.   (apply 'widget-apply (car (widget-get (widget-get widget :parent) :children))
  1914.      :mouse-down-action args))
  1915.  
  1916. (defun custom-variable-state-set (widget)
  1917.   "Set the state of WIDGET."
  1918.   (let* ((symbol (widget-value widget))
  1919.      (get (or (get symbol 'custom-get) 'default-value))
  1920.      (value (if (default-boundp symbol)
  1921.             (funcall get symbol)
  1922.           (widget-get widget :value)))
  1923.      tmp
  1924.      (state (cond ((setq tmp (get symbol 'customized-value))
  1925.                (if (condition-case nil
  1926.                    (equal value (eval (car tmp)))
  1927.                  (error nil))
  1928.                'set
  1929.              'changed))
  1930.               ((setq tmp (get symbol 'saved-value))
  1931.                (if (condition-case nil
  1932.                    (equal value (eval (car tmp)))
  1933.                  (error nil))
  1934.                'saved
  1935.              'changed))
  1936.               ((setq tmp (get symbol 'standard-value))
  1937.                (if (condition-case nil
  1938.                    (equal value (eval (car tmp)))
  1939.                  (error nil))
  1940.                'standard
  1941.              'changed))
  1942.               (t 'rogue))))
  1943.     (widget-put widget :custom-state state)))
  1944.  
  1945. (defvar custom-variable-menu
  1946.   '(("Set for Current Session" custom-variable-set
  1947.      (lambda (widget)
  1948.        (eq (widget-get widget :custom-state) 'modified)))
  1949.     ("Save for Future Sessions" custom-variable-save
  1950.      (lambda (widget)
  1951.        (memq (widget-get widget :custom-state) '(modified set changed rogue))))
  1952.     ("Reset to Current" custom-redraw
  1953.      (lambda (widget)
  1954.        (and (default-boundp (widget-value widget))
  1955.         (memq (widget-get widget :custom-state) '(modified changed)))))
  1956.     ("Reset to Saved" custom-variable-reset-saved
  1957.      (lambda (widget)
  1958.        (and (get (widget-value widget) 'saved-value)
  1959.         (memq (widget-get widget :custom-state)
  1960.           '(modified set changed rogue)))))
  1961.     ("Reset to Standard Settings" custom-variable-reset-standard
  1962.      (lambda (widget)
  1963.        (and (get (widget-value widget) 'standard-value)
  1964.         (memq (widget-get widget :custom-state)
  1965.           '(modified set changed saved rogue)))))
  1966.     ("---" ignore ignore)
  1967.     ("Don't show as Lisp expression" custom-variable-edit
  1968.      (lambda (widget)
  1969.        (eq (widget-get widget :custom-form) 'lisp)))
  1970.     ("Show as Lisp expression" custom-variable-edit-lisp
  1971.      (lambda (widget)
  1972.        (eq (widget-get widget :custom-form) 'edit))))
  1973.   "Alist of actions for the `custom-variable' widget.
  1974. Each entry has the form (NAME ACTION FILTER) where NAME is the name of
  1975. the menu entry, ACTION is the function to call on the widget when the
  1976. menu is selected, and FILTER is a predicate which takes a `custom-variable'
  1977. widget as an argument, and returns non-nil if ACTION is valid on that
  1978. widget. If FILTER is nil, ACTION is always valid.")
  1979.  
  1980. (defun custom-variable-action (widget &optional event)
  1981.   "Show the menu for `custom-variable' WIDGET.
  1982. Optional EVENT is the location for the menu."
  1983.   (if (eq (widget-get widget :custom-state) 'hidden)
  1984.       (custom-toggle-hide widget)
  1985.     (unless (eq (widget-get widget :custom-state) 'modified)
  1986.       (custom-variable-state-set widget))
  1987.     ;; Redrawing magic also depresses the state glyph.
  1988.     ;(custom-redraw-magic widget)
  1989.     (let* ((completion-ignore-case t)
  1990.        (answer (widget-choose (concat "Operation on "
  1991.                       (custom-unlispify-tag-name
  1992.                        (widget-get widget :value)))
  1993.                   (custom-menu-filter custom-variable-menu
  1994.                               widget)
  1995.                   event)))
  1996.       (if answer
  1997.       (funcall answer widget)))))
  1998.  
  1999. (defun custom-variable-edit (widget)
  2000.   "Edit value of WIDGET."
  2001.   (widget-put widget :custom-state 'unknown)
  2002.   (widget-put widget :custom-form 'edit)
  2003.   (custom-redraw widget))
  2004.  
  2005. (defun custom-variable-edit-lisp (widget)
  2006.   "Edit the lisp representation of the value of WIDGET."
  2007.   (widget-put widget :custom-state 'unknown)
  2008.   (widget-put widget :custom-form 'lisp)
  2009.   (custom-redraw widget))
  2010.  
  2011. (defun custom-variable-set (widget)
  2012.   "Set the current value for the variable being edited by WIDGET."
  2013.   (let* ((form (widget-get widget :custom-form))
  2014.      (state (widget-get widget :custom-state))
  2015.      (child (car (widget-get widget :children)))
  2016.      (symbol (widget-value widget))
  2017.      (set (or (get symbol 'custom-set) 'set-default))
  2018.       val)
  2019.     (cond ((eq state 'hidden)
  2020.        (error "Cannot set hidden variable."))
  2021.       ((setq val (widget-apply child :validate))
  2022.        (goto-char (widget-get val :from))
  2023.        (error "%s" (widget-get val :error)))
  2024.       ((memq form '(lisp mismatch))
  2025.        (funcall set symbol (eval (setq val (widget-value child))))
  2026.        (put symbol 'customized-value (list val)))
  2027.       (t
  2028.        (funcall set symbol (setq val (widget-value child)))
  2029.        (put symbol 'customized-value (list (custom-quote val)))))
  2030.     (custom-variable-state-set widget)
  2031.     (custom-redraw-magic widget)))
  2032.  
  2033. (defun custom-variable-save (widget)
  2034.   "Set and save the value for the variable being edited by WIDGET."
  2035.   (let* ((form (widget-get widget :custom-form))
  2036.      (state (widget-get widget :custom-state))
  2037.      (child (car (widget-get widget :children)))
  2038.      (symbol (widget-value widget))
  2039.      (set (or (get symbol 'custom-set) 'set-default))
  2040.      val)
  2041.     (cond ((eq state 'hidden)
  2042.        (error "Cannot set hidden variable."))
  2043.       ((setq val (widget-apply child :validate))
  2044.        (goto-char (widget-get val :from))
  2045.        (error "%s" (widget-get val :error)))
  2046.       ((memq form '(lisp mismatch))
  2047.        (put symbol 'saved-value (list (widget-value child)))
  2048.        (funcall set symbol (eval (widget-value child))))
  2049.       (t
  2050.        (put symbol
  2051.         'saved-value (list (custom-quote (widget-value
  2052.                           child))))
  2053.        (funcall set symbol (widget-value child))))
  2054.     (put symbol 'customized-value nil)
  2055.     (custom-save-all)
  2056.     (custom-variable-state-set widget)
  2057.     (custom-redraw-magic widget)))
  2058.  
  2059. (defun custom-variable-reset-saved (widget)
  2060.   "Restore the saved value for the variable being edited by WIDGET."
  2061.   (let* ((symbol (widget-value widget))
  2062.      (set (or (get symbol 'custom-set) 'set-default)))
  2063.     (if (get symbol 'saved-value)
  2064.     (condition-case nil
  2065.         (funcall set symbol (eval (car (get symbol 'saved-value))))
  2066.       (error nil))
  2067.       (error "No saved value for %s" symbol))
  2068.     (put symbol 'customized-value nil)
  2069.     (widget-put widget :custom-state 'unknown)
  2070.     (custom-redraw widget)))
  2071.  
  2072. (defun custom-variable-reset-standard (widget)
  2073.   "Restore the standard setting for the variable being edited by WIDGET."
  2074.   (let* ((symbol (widget-value widget))
  2075.      (set (or (get symbol 'custom-set) 'set-default)))
  2076.     (if (get symbol 'standard-value)
  2077.     (funcall set symbol (eval (car (get symbol 'standard-value))))
  2078.       (error "No standard setting known for %S" symbol))
  2079.     (put symbol 'customized-value nil)
  2080.     (when (get symbol 'saved-value)
  2081.       (put symbol 'saved-value nil)
  2082.       (custom-save-all))
  2083.     (widget-put widget :custom-state 'unknown)
  2084.     (custom-redraw widget)))
  2085.  
  2086. ;;; The `custom-face-edit' Widget.
  2087.  
  2088. (define-widget 'custom-face-edit 'checklist
  2089.   "Edit face attributes."
  2090.   :format "%t: %v"
  2091.   :tag "Attributes"
  2092.   :extra-offset 12
  2093.   :button-args '(:help-echo "Control whether this attribute have any effect")
  2094.   :args (mapcar (lambda (att)
  2095.           (list 'group
  2096.             :inline t
  2097.             :sibling-args (widget-get (nth 1 att) :sibling-args)
  2098.             (list 'const :format "" :value (nth 0 att))
  2099.             (nth 1 att)))
  2100.         custom-face-attributes))
  2101.  
  2102. ;;; The `custom-display' Widget.
  2103.  
  2104. (define-widget 'custom-display 'menu-choice
  2105.   "Select a display type."
  2106.   :tag "Display"
  2107.   :value t
  2108.   :help-echo "Specify frames where the face attributes should be used"
  2109.   :args '((const :tag "all" t)
  2110.       (checklist
  2111.        :offset 0
  2112.        :extra-offset 9
  2113.        :args ((group :sibling-args (:help-echo "\
  2114. Only match the specified window systems")
  2115.              (const :format "Type: "
  2116.                 type)
  2117.              (checklist :inline t
  2118.                     :offset 0
  2119.                     (const :format "X "
  2120.                        :sibling-args (:help-echo "\
  2121. The X11 Window System")
  2122.                        x)
  2123.                     (const :format "PM "
  2124.                        :sibling-args (:help-echo "\
  2125. OS/2 Presentation Manager")
  2126.                        pm)
  2127.                     (const :format "Win32 "
  2128.                        :sibling-args (:help-echo "\
  2129. Windows NT/95/97")
  2130.                        win32)
  2131.                     (const :format "DOS "
  2132.                        :sibling-args (:help-echo "\
  2133. Plain MS-DOS")
  2134.                        pc)
  2135.                     (const :format "TTY%n"
  2136.                        :sibling-args (:help-echo "\
  2137. Plain text terminals")
  2138.                        tty)))
  2139.           (group :sibling-args (:help-echo "\
  2140. Only match the frames with the specified color support")
  2141.              (const :format "Class: "
  2142.                 class)
  2143.              (checklist :inline t
  2144.                     :offset 0
  2145.                     (const :format "Color "
  2146.                        :sibling-args (:help-echo "\
  2147. Match color frames")
  2148.                        color)
  2149.                     (const :format "Grayscale "
  2150.                        :sibling-args (:help-echo "\
  2151. Match grayscale frames")
  2152.                        grayscale)
  2153.                     (const :format "Monochrome%n"
  2154.                        :sibling-args (:help-echo "\
  2155. Match frames with no color support")
  2156.                        mono)))
  2157.           (group :sibling-args (:help-echo "\
  2158. Only match frames with the specified intensity")
  2159.              (const :format "\
  2160. Background brightness: "
  2161.                 background)
  2162.              (checklist :inline t
  2163.                     :offset 0
  2164.                     (const :format "Light "
  2165.                        :sibling-args (:help-echo "\
  2166. Match frames with light backgrounds")
  2167.                        light)
  2168.                     (const :format "Dark\n"
  2169.                        :sibling-args (:help-echo "\
  2170. Match frames with dark backgrounds")
  2171.                        dark)))))))
  2172.  
  2173. ;;; The `custom-face' Widget.
  2174.  
  2175. (defface custom-face-tag-face '((t (:underline t)))
  2176.   "Face used for face tags."
  2177.   :group 'custom-faces)
  2178.  
  2179. (define-widget 'custom-face 'custom
  2180.   "Customize face."
  2181.   :sample-face 'custom-face-tag-face
  2182.   :help-echo "Set or reset this face"
  2183.   :documentation-property '(lambda (face)
  2184.                  (face-doc-string face))
  2185.   :value-create 'custom-face-value-create
  2186.   :action 'custom-face-action
  2187.   :custom-category 'face
  2188.   :custom-form 'selected
  2189.   :custom-set 'custom-face-set
  2190.   :custom-save 'custom-face-save
  2191.   :custom-reset-current 'custom-redraw
  2192.   :custom-reset-saved 'custom-face-reset-saved
  2193.   :custom-reset-standard 'custom-face-reset-standard
  2194.   :custom-menu 'custom-face-menu-create)
  2195.  
  2196. (define-widget 'custom-face-all 'editable-list
  2197.   "An editable list of display specifications and attributes."
  2198.   :entry-format "%i %d %v"
  2199.   :insert-button-args '(:help-echo "Insert new display specification here")
  2200.   :append-button-args '(:help-echo "Append new display specification here")
  2201.   :delete-button-args '(:help-echo "Delete this display specification")
  2202.   :args '((group :format "%v" custom-display custom-face-edit)))
  2203.  
  2204. (defconst custom-face-all (widget-convert 'custom-face-all)
  2205.   "Converted version of the `custom-face-all' widget.")
  2206.  
  2207. (define-widget 'custom-display-unselected 'item
  2208.   "A display specification that doesn't match the selected display."
  2209.   :match 'custom-display-unselected-match)
  2210.  
  2211. (defun custom-display-unselected-match (widget value)
  2212.   "Non-nil if VALUE is an unselected display specification."
  2213.   (not (face-spec-set-match-display value (selected-frame))))
  2214.  
  2215. (define-widget 'custom-face-selected 'group
  2216.   "Edit the attributes of the selected display in a face specification."
  2217.   :args '((repeat :format ""
  2218.           :inline t
  2219.           (group custom-display-unselected sexp))
  2220.       (group (sexp :format "") custom-face-edit)
  2221.       (repeat :format ""
  2222.           :inline t
  2223.           sexp)))
  2224.  
  2225. (defconst custom-face-selected (widget-convert 'custom-face-selected)
  2226.   "Converted version of the `custom-face-selected' widget.")
  2227.  
  2228. (defun custom-face-value-create (widget)
  2229.   "Create a list of the display specifications for WIDGET."
  2230.   (let ((buttons (widget-get widget :buttons))
  2231.     (symbol (widget-get widget :value))
  2232.     (tag (widget-get widget :tag))
  2233.     (state (widget-get widget :custom-state))
  2234.     (begin (point))
  2235.     (is-last (widget-get widget :custom-last))
  2236.     (prefix (widget-get widget :custom-prefix)))
  2237.     (unless tag
  2238.       (setq tag (prin1-to-string symbol)))
  2239.     (cond ((eq custom-buffer-style 'tree)
  2240.        (insert prefix (if is-last " `--- " " |--- "))
  2241.        (push (widget-create-child-and-convert
  2242.           widget 'custom-browse-face-tag)
  2243.          buttons)
  2244.        (insert " " tag "\n")
  2245.        (widget-put widget :buttons buttons))
  2246.       (t
  2247.        ;; Create tag.
  2248.        (insert tag)
  2249.        (if (eq custom-buffer-style 'face)
  2250.            (insert " ")
  2251.          (widget-specify-sample widget begin (point))
  2252.          (insert ": "))
  2253.        ;; Sample.
  2254.        (and (not (find-face symbol))
  2255.         ;; XEmacs cannot display uninitialized faces.
  2256.         (make-face symbol))
  2257.        (push (widget-create-child-and-convert widget 'item
  2258.                           :format "(%{%t%})"
  2259.                           :sample-face symbol
  2260.                           :tag "sample")
  2261.          buttons)
  2262.        ;; Visibility.
  2263.        (insert " ")
  2264.        (push (widget-create-child-and-convert
  2265.           widget 'visibility
  2266.           :help-echo "Hide or show this face"
  2267.           :action 'custom-toggle-parent
  2268.           (not (eq state 'hidden)))
  2269.          buttons)
  2270.        ;; Magic.
  2271.        (insert "\n")
  2272.        (let ((magic (widget-create-child-and-convert
  2273.              widget 'custom-magic nil)))
  2274.          (widget-put widget :custom-magic magic)
  2275.          (push magic buttons))
  2276.        ;; Update buttons.
  2277.        (widget-put widget :buttons buttons)
  2278.        ;; Insert documentation.
  2279.        (widget-default-format-handler widget ?h)
  2280.        ;; See also.
  2281.        (unless (eq state 'hidden)
  2282.          (when (eq (widget-get widget :custom-level) 1)
  2283.            (custom-add-parent-links widget))
  2284.          (custom-add-see-also widget))
  2285.        ;; Editor.
  2286.        (unless (eq (preceding-char) ?\n)
  2287.          (insert "\n"))
  2288.        (unless (eq state 'hidden)
  2289.          (message "Creating face editor...")
  2290.          (custom-load-widget widget)
  2291.          (let* ((symbol (widget-value widget))
  2292.             (spec (or (get symbol 'saved-face)
  2293.                   (get symbol 'face-defface-spec)
  2294.                   ;; Attempt to construct it.
  2295.                   (list (list t (face-custom-attributes-get
  2296.                          symbol (selected-frame))))))
  2297.             (form (widget-get widget :custom-form))
  2298.             (indent (widget-get widget :indent))
  2299.             (edit (widget-create-child-and-convert
  2300.                widget
  2301.                (cond ((and (eq form 'selected)
  2302.                        (widget-apply custom-face-selected
  2303.                              :match spec))
  2304.                   (when indent (insert-char ?\  indent))
  2305.                   'custom-face-selected)
  2306.                  ((and (not (eq form 'lisp))
  2307.                        (widget-apply custom-face-all
  2308.                              :match spec))
  2309.                   'custom-face-all)
  2310.                  (t
  2311.                   (when indent (insert-char ?\  indent))
  2312.                   'sexp))
  2313.                :value spec)))
  2314.            (custom-face-state-set widget)
  2315.            (widget-put widget :children (list edit)))
  2316.          (message "Creating face editor...done"))))))
  2317.  
  2318. (defvar custom-face-menu
  2319.   '(("Set for Current Session" custom-face-set)
  2320.     ("Save for Future Sessions" custom-face-save)
  2321.     ("Reset to Saved" custom-face-reset-saved
  2322.      (lambda (widget)
  2323.        (get (widget-value widget) 'saved-face)))
  2324.     ("Reset to Standard Setting" custom-face-reset-standard
  2325.      (lambda (widget)
  2326.        (get (widget-value widget) 'face-defface-spec)))
  2327.     ("---" ignore ignore)
  2328.     ("Show all display specs" custom-face-edit-all
  2329.      (lambda (widget)
  2330.        (not (eq (widget-get widget :custom-form) 'all))))
  2331.     ("Just current attributes" custom-face-edit-selected
  2332.      (lambda (widget)
  2333.        (not (eq (widget-get widget :custom-form) 'selected))))
  2334.     ("Show as Lisp expression" custom-face-edit-lisp
  2335.      (lambda (widget)
  2336.        (not (eq (widget-get widget :custom-form) 'lisp)))))
  2337.   "Alist of actions for the `custom-face' widget.
  2338. Each entry has the form (NAME ACTION FILTER) where NAME is the name of
  2339. the menu entry, ACTION is the function to call on the widget when the
  2340. menu is selected, and FILTER is a predicate which takes a `custom-face'
  2341. widget as an argument, and returns non-nil if ACTION is valid on that
  2342. widget. If FILTER is nil, ACTION is always valid.")
  2343.  
  2344. (defun custom-face-edit-selected (widget)
  2345.   "Edit selected attributes of the value of WIDGET."
  2346.   (widget-put widget :custom-state 'unknown)
  2347.   (widget-put widget :custom-form 'selected)
  2348.   (custom-redraw widget))
  2349.  
  2350. (defun custom-face-edit-all (widget)
  2351.   "Edit all attributes of the value of WIDGET."
  2352.   (widget-put widget :custom-state 'unknown)
  2353.   (widget-put widget :custom-form 'all)
  2354.   (custom-redraw widget))
  2355.  
  2356. (defun custom-face-edit-lisp (widget)
  2357.   "Edit the lisp representation of the value of WIDGET."
  2358.   (widget-put widget :custom-state 'unknown)
  2359.   (widget-put widget :custom-form 'lisp)
  2360.   (custom-redraw widget))
  2361.  
  2362. (defun custom-face-state-set (widget)
  2363.   "Set the state of WIDGET."
  2364.   (let ((symbol (widget-value widget)))
  2365.     (widget-put widget :custom-state (cond ((get symbol 'customized-face)
  2366.                         'set)
  2367.                        ((get symbol 'saved-face)
  2368.                         'saved)
  2369.                        ((get symbol 'face-defface-spec)
  2370.                         'standard)
  2371.                        (t
  2372.                         'rogue)))))
  2373.  
  2374. (defun custom-face-action (widget &optional event)
  2375.   "Show the menu for `custom-face' WIDGET.
  2376. Optional EVENT is the location for the menu."
  2377.   (if (eq (widget-get widget :custom-state) 'hidden)
  2378.       (custom-toggle-hide widget)
  2379.     (let* ((completion-ignore-case t)
  2380.        (symbol (widget-get widget :value))
  2381.        (answer (widget-choose (concat "Operation on "
  2382.                       (custom-unlispify-tag-name symbol))
  2383.                   (custom-menu-filter custom-face-menu
  2384.                               widget)
  2385.                   event)))
  2386.       (if answer
  2387.       (funcall answer widget)))))
  2388.  
  2389. (defun custom-face-set (widget)
  2390.   "Make the face attributes in WIDGET take effect."
  2391.   (let* ((symbol (widget-value widget))
  2392.      (child (car (widget-get widget :children)))
  2393.      (value (widget-value child)))
  2394.     (put symbol 'customized-face value)
  2395.     (face-spec-set symbol value)
  2396.     (custom-face-state-set widget)
  2397.     (custom-redraw-magic widget)))
  2398.  
  2399. (defun custom-face-save (widget)
  2400.   "Make the face attributes in WIDGET default."
  2401.   (let* ((symbol (widget-value widget))
  2402.      (child (car (widget-get widget :children)))
  2403.      (value (widget-value child)))
  2404.     (face-spec-set symbol value)
  2405.     (put symbol 'saved-face value)
  2406.     (put symbol 'customized-face nil)
  2407.     (custom-save-all)
  2408.     (custom-face-state-set widget)
  2409.     (custom-redraw-magic widget)))
  2410.  
  2411. (defun custom-face-reset-saved (widget)
  2412.   "Restore WIDGET to the face's default attributes."
  2413.   (let* ((symbol (widget-value widget))
  2414.      (child (car (widget-get widget :children)))
  2415.      (value (get symbol 'saved-face)))
  2416.     (unless value
  2417.       (error "No saved value for this face"))
  2418.     (put symbol 'customized-face nil)
  2419.     (face-spec-set symbol value)
  2420.     (widget-value-set child value)
  2421.     (custom-face-state-set widget)
  2422.     (custom-redraw-magic widget)))
  2423.  
  2424. (defun custom-face-reset-standard (widget)
  2425.   "Restore WIDGET to the face's standard settings."
  2426.   (let* ((symbol (widget-value widget))
  2427.      (child (car (widget-get widget :children)))
  2428.      (value (get symbol 'face-defface-spec)))
  2429.     (unless value
  2430.       (error "No standard setting for this face"))
  2431.     (put symbol 'customized-face nil)
  2432.     (when (get symbol 'saved-face)
  2433.       (put symbol 'saved-face nil)
  2434.       (custom-save-all))
  2435.     (face-spec-set symbol value)
  2436.     (widget-value-set child value)
  2437.     (custom-face-state-set widget)
  2438.     (custom-redraw-magic widget)))
  2439.  
  2440. ;;; The `face' Widget.
  2441.  
  2442. (define-widget 'face 'default
  2443.   "Select and customize a face."
  2444.   :convert-widget 'widget-value-convert-widget
  2445.   :button-prefix 'widget-push-button-prefix
  2446.   :button-suffix 'widget-push-button-suffix
  2447.   :format "%t: %[select face%] %v"
  2448.   :tag "Face"
  2449.   :value 'default
  2450.   :value-create 'widget-face-value-create
  2451.   :value-delete 'widget-face-value-delete
  2452.   :value-get 'widget-value-value-get
  2453.   :validate 'widget-children-validate
  2454.   :action 'widget-face-action
  2455.   :match (lambda (widget value) (symbolp value)))
  2456.  
  2457. (defun widget-face-value-create (widget)
  2458.   ;; Create a `custom-face' child.
  2459.   (let* ((symbol (widget-value widget))
  2460.      (custom-buffer-style 'face)
  2461.      (child (widget-create-child-and-convert
  2462.          widget 'custom-face
  2463.          :custom-level nil
  2464.          :value symbol)))
  2465.     (custom-magic-reset child)
  2466.     (setq custom-options (cons child custom-options))
  2467.     (widget-put widget :children (list child))))
  2468.  
  2469. (defun widget-face-value-delete (widget)
  2470.   ;; Remove the child from the options.
  2471.   (let ((child (car (widget-get widget :children))))
  2472.     (setq custom-options (delq child custom-options))
  2473.     (widget-children-value-delete widget)))
  2474.  
  2475. (defvar face-history nil
  2476.   "History of entered face names.")
  2477.  
  2478. (defun widget-face-action (widget &optional event)
  2479.   "Prompt for a face."
  2480.   (let ((answer (completing-read "Face: "
  2481.                  (mapcar (lambda (face)
  2482.                        (list (symbol-name face)))
  2483.                      (face-list))
  2484.                  nil nil nil
  2485.                  'face-history)))
  2486.     (unless (zerop (length answer))
  2487.       (widget-value-set widget (intern answer))
  2488.       (widget-apply widget :notify widget event)
  2489.       (widget-setup))))
  2490.  
  2491. ;;; The `hook' Widget.
  2492.  
  2493. (define-widget 'hook 'list
  2494.   "A emacs lisp hook"
  2495.   :value-to-internal (lambda (widget value)
  2496.                (if (symbolp value)
  2497.                (list value)
  2498.              value))
  2499.   :match (lambda (widget value)
  2500.        (or (symbolp value)
  2501.            (widget-group-match widget value)))
  2502.   :convert-widget 'custom-hook-convert-widget
  2503.   :tag "Hook")
  2504.  
  2505. (defun custom-hook-convert-widget (widget)
  2506.   ;; Handle `:custom-options'.
  2507.   (let* ((options (widget-get widget :options))
  2508.      (other `(editable-list :inline t
  2509.                 :entry-format "%i %d%v"
  2510.                 (function :format " %v")))
  2511.      (args (if options
  2512.            (list `(checklist :inline t
  2513.                      ,@(mapcar (lambda (entry)
  2514.                          `(function-item ,entry))
  2515.                            options))
  2516.              other)
  2517.          (list other))))
  2518.     (widget-put widget :args args)
  2519.     widget))
  2520.  
  2521. ;;; The `custom-group-link' Widget.
  2522.  
  2523. (define-widget 'custom-group-link 'link
  2524.   "Show parent in other window when activated."
  2525.   :help-echo 'custom-group-link-help-echo
  2526.   :action 'custom-group-link-action)
  2527.  
  2528. (defun custom-group-link-help-echo (widget)
  2529.   (concat "Create customization buffer for the `"
  2530.       (custom-unlispify-tag-name (widget-value widget))
  2531.       "' group"))
  2532.  
  2533. (defun custom-group-link-action (widget &rest ignore)
  2534.   (customize-group (widget-value widget)))
  2535.  
  2536. ;;; The `custom-group' Widget.
  2537.  
  2538. (defcustom custom-group-tag-faces nil
  2539.   ;; In XEmacs, this ought to play games with font size.
  2540.   "Face used for group tags.
  2541. The first member is used for level 1 groups, the second for level 2,
  2542. and so forth.  The remaining group tags are shown with
  2543. `custom-group-tag-face'."
  2544.   :type '(repeat face)
  2545.   :group 'custom-faces)
  2546.  
  2547. (defface custom-group-tag-face-1 '((((class color)
  2548.                      (background dark))
  2549.                     (:foreground "pink" :underline t))
  2550.                    (((class color)
  2551.                      (background light))
  2552.                     (:foreground "red" :underline t))
  2553.                    (t (:underline t)))
  2554.   "Face used for group tags.")
  2555.  
  2556. (defface custom-group-tag-face '((((class color)
  2557.                    (background dark))
  2558.                   (:foreground "light blue" :underline t))
  2559.                  (((class color)
  2560.                    (background light))
  2561.                   (:foreground "blue" :underline t))
  2562.                  (t (:underline t)))
  2563.   "Face used for low level group tags."
  2564.   :group 'custom-faces)
  2565.  
  2566. (define-widget 'custom-group 'custom
  2567.   "Customize group."
  2568.   :format "%v"
  2569.   :sample-face-get 'custom-group-sample-face-get
  2570.   :documentation-property 'group-documentation
  2571.   :help-echo "Set or reset all members of this group"
  2572.   :value-create 'custom-group-value-create
  2573.   :action 'custom-group-action
  2574.   :custom-category 'group
  2575.   :custom-set 'custom-group-set
  2576.   :custom-save 'custom-group-save
  2577.   :custom-reset-current 'custom-group-reset-current
  2578.   :custom-reset-saved 'custom-group-reset-saved
  2579.   :custom-reset-standard 'custom-group-reset-standard
  2580.   :custom-menu 'custom-group-menu-create)
  2581.  
  2582. (defun custom-group-sample-face-get (widget)
  2583.   ;; Use :sample-face.
  2584.   (or (nth (1- (widget-get widget :custom-level)) custom-group-tag-faces)
  2585.       'custom-group-tag-face))
  2586.  
  2587. (define-widget 'custom-group-visibility 'visibility
  2588.   "An indicator and manipulator for hidden group contents."
  2589.   :create 'custom-group-visibility-create)
  2590.  
  2591. (defun custom-group-visibility-create (widget)
  2592.   (let ((visible (widget-value widget)))
  2593.     (if visible
  2594.     (insert "--------")))
  2595.   (widget-default-create widget))
  2596.  
  2597. (defun custom-group-members (symbol groups-only)
  2598.   "Return SYMBOL's custom group members.
  2599. If GROUPS-ONLY non-nil, return only those members that are groups."
  2600.   (if (not groups-only)
  2601.       (get symbol 'custom-group)
  2602.     (let (members)
  2603.       (dolist (entry (get symbol 'custom-group) (nreverse members))
  2604.     (when (eq (nth 1 entry) 'custom-group)
  2605.       (push entry members))))))
  2606.  
  2607. (defun custom-group-value-create (widget)
  2608.   "Insert a customize group for WIDGET in the current buffer."
  2609.   (let* ((state (widget-get widget :custom-state))
  2610.      (level (widget-get widget :custom-level))
  2611.      ;; (indent (widget-get widget :indent))
  2612.      (prefix (widget-get widget :custom-prefix))
  2613.      (buttons (widget-get widget :buttons))
  2614.      (tag (widget-get widget :tag))
  2615.      (symbol (widget-value widget))
  2616.      (members (custom-group-members symbol
  2617.                     (and (eq custom-buffer-style 'tree)
  2618.                          custom-browse-only-groups))))
  2619.     (cond ((and (eq custom-buffer-style 'tree)
  2620.         (eq state 'hidden)
  2621.         (or members (custom-unloaded-widget-p widget)))
  2622.        (custom-browse-insert-prefix prefix)
  2623.        (push (widget-create-child-and-convert
  2624.           widget 'custom-browse-visibility
  2625.           ;; :tag-glyph "plus"
  2626.           :tag "+")
  2627.          buttons)
  2628.        (insert "-- ")
  2629.        ;; (widget-glyph-insert nil "-- " "horizontal")
  2630.        (push (widget-create-child-and-convert
  2631.           widget 'custom-browse-group-tag)
  2632.          buttons)
  2633.        (insert " " tag "\n")
  2634.        (widget-put widget :buttons buttons))
  2635.       ((and (eq custom-buffer-style 'tree)
  2636.         (zerop (length members)))
  2637.        (custom-browse-insert-prefix prefix)
  2638.        (insert "[ ]-- ")
  2639.        ;; (widget-glyph-insert nil "[ ]" "empty")
  2640.        ;; (widget-glyph-insert nil "-- " "horizontal")
  2641.        (push (widget-create-child-and-convert
  2642.           widget 'custom-browse-group-tag)
  2643.          buttons)
  2644.        (insert " " tag "\n")
  2645.        (widget-put widget :buttons buttons))
  2646.       ((eq custom-buffer-style 'tree)
  2647.        (custom-browse-insert-prefix prefix)
  2648.        (custom-load-widget widget)
  2649.        (if (zerop (length members))
  2650.            (progn
  2651.          (custom-browse-insert-prefix prefix)
  2652.          (insert "[ ]-- ")
  2653.          ;; (widget-glyph-insert nil "[ ]" "empty")
  2654.          ;; (widget-glyph-insert nil "-- " "horizontal")
  2655.          (push (widget-create-child-and-convert
  2656.             widget 'custom-browse-group-tag)
  2657.                buttons)
  2658.          (insert " " tag "\n")
  2659.          (widget-put widget :buttons buttons))
  2660.          (push (widget-create-child-and-convert
  2661.             widget 'custom-browse-visibility
  2662.             ;; :tag-glyph "minus"
  2663.             :tag "-")
  2664.            buttons)
  2665.          (insert "-\\ ")
  2666.          ;; (widget-glyph-insert nil "-\\ " "top")
  2667.          (push (widget-create-child-and-convert
  2668.             widget 'custom-browse-group-tag)
  2669.            buttons)
  2670.          (insert " " tag "\n")
  2671.          (widget-put widget :buttons buttons)
  2672.          (message "Creating group...")
  2673.          (let* ((members (custom-sort-items members
  2674.                   custom-browse-sort-alphabetically
  2675.                   custom-browse-order-groups))
  2676.             (prefixes (widget-get widget :custom-prefixes))
  2677.             (custom-prefix-list (custom-prefix-add symbol prefixes))
  2678.             (extra-prefix (if (widget-get widget :custom-last)
  2679.                       "   "
  2680.                     " | "))
  2681.             (prefix (concat prefix extra-prefix))
  2682.             children entry)
  2683.            (while members
  2684.          (setq entry (car members)
  2685.                members (cdr members))
  2686.          (push (widget-create-child-and-convert
  2687.             widget (nth 1 entry)
  2688.             :group widget
  2689.             :tag (custom-unlispify-tag-name (nth 0 entry))
  2690.             :custom-prefixes custom-prefix-list
  2691.             :custom-level (1+ level)
  2692.             :custom-last (null members)
  2693.             :value (nth 0 entry)
  2694.             :custom-prefix prefix)
  2695.                children))
  2696.            (widget-put widget :children (reverse children)))
  2697.          (message "Creating group...done")))
  2698.       ;; Nested style.
  2699.       ((eq state 'hidden)
  2700.        ;; Create level indicator.
  2701.        (unless (eq custom-buffer-style 'links)
  2702.          (insert-char ?\  (* custom-buffer-indent (1- level)))
  2703.          (insert "-- "))
  2704.        ;; Create link indicator.
  2705.        (when (eq custom-buffer-style 'links)
  2706.          (insert " ")
  2707.          (push (widget-create-child-and-convert
  2708.             widget 'custom-group-link
  2709.             :tag "Open"
  2710.             :tag-glyph '("open-up" "open-down")
  2711.             symbol)
  2712.            buttons)
  2713.          (insert " "))
  2714.        ;; Create tag.
  2715.        (let ((begin (point)))
  2716.          (insert tag)
  2717.          (widget-specify-sample widget begin (point)))
  2718.        (insert " group")
  2719.        ;; Create visibility indicator.
  2720.        (unless (eq custom-buffer-style 'links)
  2721.          (insert ": ")
  2722.          (push (widget-create-child-and-convert
  2723.             widget 'custom-group-visibility
  2724.             :help-echo "Show members of this group"
  2725.             :action 'custom-toggle-parent
  2726.             (not (eq state 'hidden)))
  2727.            buttons))
  2728.        (insert " \n")
  2729.        ;; Create magic button.
  2730.        (let ((magic (widget-create-child-and-convert
  2731.              widget 'custom-magic nil)))
  2732.          (widget-put widget :custom-magic magic)
  2733.          (push magic buttons))
  2734.        ;; Update buttons.
  2735.        (widget-put widget :buttons buttons)
  2736.        ;; Insert documentation.
  2737.        (if (and (eq custom-buffer-style 'links) (> level 1))
  2738.            (widget-put widget :documentation-indent 0))
  2739.        (widget-default-format-handler widget ?h))
  2740.       ;; Nested style.
  2741.       (t                ;Visible.
  2742.        (custom-load-widget widget)
  2743.        ;; Update members
  2744.        (setq members (custom-group-members
  2745.               symbol (and (eq custom-buffer-style 'tree)
  2746.                       custom-browse-only-groups)))
  2747.        ;; Add parent groups references above the group.
  2748.        (if t    ;;; This should test that the buffer
  2749.             ;;; was made to display a group.
  2750.            (when (eq level 1)
  2751.          (if (custom-add-parent-links widget
  2752.                           "Go to parent group:")
  2753.              (insert "\n"))))
  2754.        ;; Create level indicator.
  2755.        (insert-char ?\  (* custom-buffer-indent (1- level)))
  2756.        (insert "/- ")
  2757.        ;; Create tag.
  2758.        (let ((start (point)))
  2759.          (insert tag)
  2760.          (widget-specify-sample widget start (point)))
  2761.        (insert " group: ")
  2762.        ;; Create visibility indicator.
  2763.        (unless (eq custom-buffer-style 'links)
  2764.          (insert "--------")
  2765.          (push (widget-create-child-and-convert
  2766.             widget 'visibility
  2767.             :help-echo "Hide members of this group"
  2768.             :action 'custom-toggle-parent
  2769.             (not (eq state 'hidden)))
  2770.            buttons)
  2771.          (insert " "))
  2772.        ;; Create more dashes.
  2773.        ;; Use 76 instead of 75 to compensate for the temporary "<"
  2774.        ;; added by `widget-insert'.
  2775.        (insert-char ?- (- 76 (current-column)
  2776.                   (* custom-buffer-indent level)))
  2777.        (insert "\\\n")
  2778.        ;; Create magic button.
  2779.        (let ((magic (widget-create-child-and-convert
  2780.              widget 'custom-magic
  2781.              :indent 0
  2782.              nil)))
  2783.          (widget-put widget :custom-magic magic)
  2784.          (push magic buttons))
  2785.        ;; Update buttons.
  2786.        (widget-put widget :buttons buttons)
  2787.        ;; Insert documentation.
  2788.        (widget-default-format-handler widget ?h)
  2789.        ;; Parent groups.
  2790.        (if nil  ;;; This should test that the buffer
  2791.             ;;; was not made to display a group.
  2792.            (when (eq level 1)
  2793.          (insert-char ?\  custom-buffer-indent)
  2794.          (custom-add-parent-links widget)))
  2795.        (custom-add-see-also widget
  2796.                 (make-string (* custom-buffer-indent level)
  2797.                          ?\ ))
  2798.        ;; Members.
  2799.        (message "Creating group...")
  2800.        (let* ((members (custom-sort-items members
  2801.                           custom-buffer-sort-alphabetically
  2802.                           custom-buffer-order-groups))
  2803.           (prefixes (widget-get widget :custom-prefixes))
  2804.           (custom-prefix-list (custom-prefix-add symbol prefixes))
  2805.           (length (length members))
  2806.           (count 0)
  2807.           (children (mapcar
  2808.                  (lambda (entry)
  2809.                    (widget-insert "\n")
  2810.                    (when (zerop (% count custom-skip-messages))
  2811.                  (display-message
  2812.                   'progress
  2813.                   (format "\
  2814. Creating group members... %2d%%"
  2815.                       (/ (* 100.0 count) length))))
  2816.                    (incf count)
  2817.                    (prog1
  2818.                    (widget-create-child-and-convert
  2819.                     widget (nth 1 entry)
  2820.                     :group widget
  2821.                     :tag (custom-unlispify-tag-name
  2822.                       (nth 0 entry))
  2823.                     :custom-prefixes custom-prefix-list
  2824.                     :custom-level (1+ level)
  2825.                     :value (nth 0 entry))
  2826.                  (unless (eq (preceding-char) ?\n)
  2827.                    (widget-insert "\n"))))
  2828.                  members)))
  2829.          (message "Creating group magic...")
  2830.          (mapc 'custom-magic-reset children)
  2831.          (message "Creating group state...")
  2832.          (widget-put widget :children children)
  2833.          (custom-group-state-update widget)
  2834.          (message "Creating group... done"))
  2835.        ;; End line
  2836.        (insert "\n")
  2837.        (insert-char ?\  (* custom-buffer-indent (1- level)))
  2838.        (insert "\\- " (widget-get widget :tag) " group end ")
  2839.        (insert-char ?- (- 75 (current-column) (* custom-buffer-indent level)))
  2840.        (insert "/\n")))))
  2841.  
  2842. (defvar custom-group-menu
  2843.   '(("Set for Current Session" custom-group-set
  2844.      (lambda (widget)
  2845.        (eq (widget-get widget :custom-state) 'modified)))
  2846.     ("Save for Future Sessions" custom-group-save
  2847.      (lambda (widget)
  2848.        (memq (widget-get widget :custom-state) '(modified set))))
  2849.     ("Reset to Current" custom-group-reset-current
  2850.      (lambda (widget)
  2851.        (memq (widget-get widget :custom-state) '(modified))))
  2852.     ("Reset to Saved" custom-group-reset-saved
  2853.      (lambda (widget)
  2854.        (memq (widget-get widget :custom-state) '(modified set))))
  2855.     ("Reset to standard setting" custom-group-reset-standard
  2856.      (lambda (widget)
  2857.        (memq (widget-get widget :custom-state) '(modified set saved)))))
  2858.   "Alist of actions for the `custom-group' widget.
  2859. Each entry has the form (NAME ACTION FILTER) where NAME is the name of
  2860. the menu entry, ACTION is the function to call on the widget when the
  2861. menu is selected, and FILTER is a predicate which takes a `custom-group'
  2862. widget as an argument, and returns non-nil if ACTION is valid on that
  2863. widget. If FILTER is nil, ACTION is always valid.")
  2864.  
  2865. (defun custom-group-action (widget &optional event)
  2866.   "Show the menu for `custom-group' WIDGET.
  2867. Optional EVENT is the location for the menu."
  2868.   (if (eq (widget-get widget :custom-state) 'hidden)
  2869.       (custom-toggle-hide widget)
  2870.     (let* ((completion-ignore-case t)
  2871.        (answer (widget-choose (concat "Operation on "
  2872.                       (custom-unlispify-tag-name
  2873.                        (widget-get widget :value)))
  2874.                   (custom-menu-filter custom-group-menu
  2875.                               widget)
  2876.                   event)))
  2877.       (if answer
  2878.       (funcall answer widget)))))
  2879.  
  2880. (defun custom-group-set (widget)
  2881.   "Set changes in all modified group members."
  2882.   (let ((children (widget-get widget :children)))
  2883.     (mapc (lambda (child)
  2884.         (when (eq (widget-get child :custom-state) 'modified)
  2885.           (widget-apply child :custom-set)))
  2886.       children)))
  2887.  
  2888. (defun custom-group-save (widget)
  2889.   "Save all modified group members."
  2890.   (let ((children (widget-get widget :children)))
  2891.     (mapc (lambda (child)
  2892.         (when (memq (widget-get child :custom-state) '(modified set))
  2893.           (widget-apply child :custom-save)))
  2894.       children)))
  2895.  
  2896. (defun custom-group-reset-current (widget)
  2897.   "Reset all modified group members."
  2898.   (let ((children (widget-get widget :children)))
  2899.     (mapc (lambda (child)
  2900.         (when (eq (widget-get child :custom-state) 'modified)
  2901.           (widget-apply child :custom-reset-current)))
  2902.       children)))
  2903.  
  2904. (defun custom-group-reset-saved (widget)
  2905.   "Reset all modified or set group members."
  2906.   (let ((children (widget-get widget :children)))
  2907.     (mapc (lambda (child)
  2908.         (when (memq (widget-get child :custom-state) '(modified set))
  2909.           (widget-apply child :custom-reset-saved)))
  2910.       children)))
  2911.  
  2912. (defun custom-group-reset-standard (widget)
  2913.   "Reset all modified, set, or saved group members."
  2914.   (let ((children (widget-get widget :children)))
  2915.     (mapc (lambda (child)
  2916.         (when (memq (widget-get child :custom-state)
  2917.             '(modified set saved))
  2918.           (widget-apply child :custom-reset-standard)))
  2919.       children)))
  2920.  
  2921. (defun custom-group-state-update (widget)
  2922.   "Update magic."
  2923.   (unless (eq (widget-get widget :custom-state) 'hidden)
  2924.     (let* ((children (widget-get widget :children))
  2925.        (states (mapcar (lambda (child)
  2926.                  (widget-get child :custom-state))
  2927.                children))
  2928.        (magics custom-magic-alist)
  2929.        (found 'standard))
  2930.       (while magics
  2931.     (let ((magic (car (car magics))))
  2932.       (if (and (not (eq magic 'hidden))
  2933.            (memq magic states))
  2934.           (setq found magic
  2935.             magics nil)
  2936.         (setq magics (cdr magics)))))
  2937.       (widget-put widget :custom-state found)))
  2938.   (custom-magic-reset widget))
  2939.  
  2940. ;;; The `custom-save-all' Function.
  2941. ;;;###autoload
  2942. (defcustom custom-file "~/.emacs"
  2943.   "File used for storing customization information.
  2944. If you change this from the default \"~/.emacs\" you need to
  2945. explicitly load that file for the settings to take effect."
  2946.   :type 'file
  2947.   :group 'customize)
  2948.  
  2949. (defun custom-save-delete (symbol)
  2950.   "Delete the call to SYMBOL form `custom-file'.
  2951. Leave point at the location of the call, or after the last expression."
  2952.   (let ((find-file-hooks nil)
  2953.     (auto-mode-alist nil))
  2954.     (set-buffer (find-file-noselect custom-file)))
  2955.   (goto-char (point-min))
  2956.   (catch 'found
  2957.     (while t
  2958.       (let ((sexp (condition-case nil
  2959.               (read (current-buffer))
  2960.             (end-of-file (throw 'found nil)))))
  2961.     (when (and (listp sexp)
  2962.            (eq (car sexp) symbol))
  2963.       (delete-region (save-excursion
  2964.                (backward-sexp)
  2965.                (point))
  2966.              (point))
  2967.       (throw 'found nil))))))
  2968.  
  2969. (defun custom-save-variables ()
  2970.   "Save all customized variables in `custom-file'."
  2971.   (save-excursion
  2972.     (custom-save-delete 'custom-set-variables)
  2973.     (let ((standard-output (current-buffer)))
  2974.       (unless (bolp)
  2975.     (princ "\n"))
  2976.       (princ "(custom-set-variables")
  2977.       (mapatoms (lambda (symbol)
  2978.           (let ((value (get symbol 'saved-value))
  2979.             (requests (get symbol 'custom-requests))
  2980.             (now (not (or (get symbol 'standard-value)
  2981.                       (and (not (boundp symbol))
  2982.                        (not (get symbol 'force-value)))))))
  2983.             (when value
  2984.               (princ "\n '(")
  2985.               (princ symbol)
  2986.               (princ " ")
  2987.               (prin1 (car value))
  2988.               (cond (requests
  2989.                  (if now
  2990.                  (princ " t ")
  2991.                    (princ " nil "))
  2992.                  (prin1 requests)
  2993.                  (princ ")"))
  2994.                 (now
  2995.                  (princ " t)"))
  2996.                 (t
  2997.                  (princ ")")))))))
  2998.       (princ ")")
  2999.       (unless (looking-at "\n")
  3000.     (princ "\n")))))
  3001.  
  3002. (defun custom-save-faces ()
  3003.   "Save all customized faces in `custom-file'."
  3004.   (save-excursion
  3005.     (custom-save-delete 'custom-set-faces)
  3006.     (let ((standard-output (current-buffer)))
  3007.       (unless (bolp)
  3008.     (princ "\n"))
  3009.       (princ "(custom-set-faces")
  3010.       (let ((value (get 'default 'saved-face)))
  3011.     ;; The default face must be first, since it affects the others.
  3012.     (when value
  3013.       (princ "\n '(default ")
  3014.       (prin1 value)
  3015.       (if (or (get 'default 'face-defface-spec)
  3016.           (and (not (find-face 'default))
  3017.                (not (get 'default 'force-face))))
  3018.           (princ ")")
  3019.         (princ " t)"))))
  3020.       (mapatoms (lambda (symbol)
  3021.           (let ((value (get symbol 'saved-face)))
  3022.             (when (and (not (eq symbol 'default))
  3023.                    ;; Don't print default face here.
  3024.                    value)
  3025.               (princ "\n '(")
  3026.               (princ symbol)
  3027.               (princ " ")
  3028.               (prin1 value)
  3029.               (if (or (get symbol 'face-defface-spec)
  3030.                   (and (not (find-face symbol))
  3031.                    (not (get symbol 'force-face))))
  3032.               (princ ")")
  3033.             (princ " t)"))))))
  3034.       (princ ")")
  3035.       (unless (looking-at "\n")
  3036.     (princ "\n")))))
  3037.  
  3038. ;;;###autoload
  3039. (defun customize-save-customized ()
  3040.   "Save all user options which have been set in this session."
  3041.   (interactive)
  3042.   (mapatoms (lambda (symbol)
  3043.           (let ((face (get symbol 'customized-face))
  3044.             (value (get symbol 'customized-value)))
  3045.         (when face
  3046.           (put symbol 'saved-face face)
  3047.           (put symbol 'customized-face nil))
  3048.         (when value
  3049.           (put symbol 'saved-value value)
  3050.           (put symbol 'customized-value nil)))))
  3051.   ;; We really should update all custom buffers here.
  3052.   (custom-save-all))
  3053.  
  3054. ;;;###autoload
  3055. (defun custom-save-all ()
  3056.   "Save all customizations in `custom-file'."
  3057.   (let ((inhibit-read-only t))
  3058.     (custom-save-variables)
  3059.     (custom-save-faces)
  3060.     (let ((find-file-hooks nil)
  3061.       (auto-mode-alist))
  3062.       (with-current-buffer (find-file-noselect custom-file)
  3063.     (save-buffer)))))
  3064.  
  3065.  
  3066. ;;; The Customize Menu.
  3067.  
  3068. ;;; Menu support
  3069.  
  3070. (defun custom-face-menu-create (widget symbol)
  3071.   "Ignoring WIDGET, create a menu entry for customization face SYMBOL."
  3072.   (vector (custom-unlispify-menu-entry symbol)
  3073.       `(customize-face ',symbol)
  3074.       t))
  3075.  
  3076. (defun custom-variable-menu-create (widget symbol)
  3077.   "Ignoring WIDGET, create a menu entry for customization variable SYMBOL."
  3078.   (let ((type (get symbol 'custom-type)))
  3079.     (unless (listp type)
  3080.       (setq type (list type)))
  3081.     (if (and type (widget-get type :custom-menu))
  3082.     (widget-apply type :custom-menu symbol)
  3083.       (vector (custom-unlispify-menu-entry symbol)
  3084.           `(customize-variable ',symbol)
  3085.           t))))
  3086.  
  3087. ;; Add checkboxes to boolean variable entries.
  3088. (widget-put (get 'boolean 'widget-type)
  3089.         :custom-menu (lambda (widget symbol)
  3090.                `[,(custom-unlispify-menu-entry symbol)
  3091.                  (customize-variable ',symbol)
  3092.                  :style toggle
  3093.                  :selected ,symbol]))
  3094.  
  3095. ;; XEmacs can create menus dynamically.
  3096. (defun custom-group-menu-create (widget symbol)
  3097.   "Ignoring WIDGET, create a menu entry for customization group SYMBOL."
  3098.   `( ,(custom-unlispify-menu-entry symbol t)
  3099.      :filter (lambda (&rest junk)
  3100.            (let ((item (custom-menu-create ',symbol)))
  3101.          (if (listp item)
  3102.              (cdr item)
  3103.            (list item))))))
  3104.  
  3105. ;;;###autoload
  3106. (defun custom-menu-create (symbol)
  3107.   "Create menu for customization group SYMBOL.
  3108. The menu is in a format applicable to `easy-menu-define'."
  3109.   (let* ((item (vector (custom-unlispify-menu-entry symbol)
  3110.                `(customize-group ',symbol)
  3111.                t)))
  3112.     ;; Item is the entry for creating a menu buffer for SYMBOL.
  3113.     ;; We may nest, if the menu is not too big.
  3114.     (custom-load-symbol symbol)
  3115.     (if (< (length (get symbol 'custom-group)) widget-menu-max-size)
  3116.     ;; The menu is not too big.
  3117.     (let ((custom-prefix-list (custom-prefix-add symbol
  3118.                              custom-prefix-list))
  3119.           (members (custom-sort-items (get symbol 'custom-group)
  3120.                       custom-menu-sort-alphabetically
  3121.                       custom-menu-order-groups)))
  3122.       ;; Create the menu.
  3123.       `(,(custom-unlispify-menu-entry symbol t)
  3124.         ,item
  3125.         "--"
  3126.         ,@(mapcar (lambda (entry)
  3127.             (widget-apply (if (listp (nth 1 entry))
  3128.                       (nth 1 entry)
  3129.                     (list (nth 1 entry)))
  3130.                       :custom-menu (nth 0 entry)))
  3131.               members)))
  3132.       ;; The menu was too big.
  3133.       item)))
  3134.  
  3135. ;;;###autoload
  3136. (defun customize-menu-create (symbol &optional name)
  3137.   "Return a customize menu for customization group SYMBOL.
  3138. If optional NAME is given, use that as the name of the menu.
  3139. Otherwise the menu will be named `Customize'.
  3140. The format is suitable for use with `easy-menu-define'."
  3141.   (unless name
  3142.     (setq name "Customize"))
  3143.   `(,name
  3144.     :filter (lambda (&rest junk)
  3145.           (cdr (custom-menu-create ',symbol)))))
  3146.  
  3147. ;;; The Custom Mode.
  3148.  
  3149. (defvar custom-mode-map nil
  3150.   "Keymap for `custom-mode'.")
  3151.  
  3152. (unless custom-mode-map
  3153.   (setq custom-mode-map (make-sparse-keymap))
  3154.   (set-keymap-parents custom-mode-map widget-keymap)
  3155.   (suppress-keymap custom-mode-map)
  3156.   (define-key custom-mode-map " " 'scroll-up)
  3157.   (define-key custom-mode-map [delete] 'scroll-down)
  3158.   (define-key custom-mode-map "q" 'Custom-buffer-done)
  3159.   (define-key custom-mode-map "u" 'Custom-goto-parent)
  3160.   (define-key custom-mode-map "n" 'widget-forward)
  3161.   (define-key custom-mode-map "p" 'widget-backward)
  3162.   ;; (define-key custom-mode-map [mouse-1] 'Custom-move-and-invoke)
  3163.   )
  3164.  
  3165. (defun Custom-move-and-invoke (event)
  3166.   "Move to where you click, and if it is an active field, invoke it."
  3167.   (interactive "e")
  3168.   (mouse-set-point event)
  3169.   (if (widget-event-point event)
  3170.       (let* ((pos (widget-event-point event))
  3171.          (button (get-char-property pos 'button)))
  3172.     (if button
  3173.         (widget-button-click event)))))
  3174.  
  3175. (easy-menu-define Custom-mode-menu
  3176.     custom-mode-map
  3177.   "Menu used in customization buffers."
  3178.   `("Custom"
  3179.     ,(customize-menu-create 'customize)
  3180.     ["Set" Custom-set t]
  3181.     ["Save" Custom-save t]
  3182.     ["Reset to Current" Custom-reset-current t]
  3183.     ["Reset to Saved" Custom-reset-saved t]
  3184.     ["Reset to Standard Settings" Custom-reset-standard t]
  3185.     ["Info" (Info-goto-node "(xemacs)Easy Customization") t]))
  3186.  
  3187. (defun Custom-goto-parent ()
  3188.   "Go to the parent group listed at the top of this buffer.
  3189. If several parents are listed, go to the first of them."
  3190.   (interactive)
  3191.   (save-excursion
  3192.     (goto-char (point-min))
  3193.     (if (search-forward "\nGo to parent group: " nil t)
  3194.     (let* ((button (get-char-property (point) 'button))
  3195.            (parent (downcase (widget-get  button :tag))))
  3196.       (customize-group parent)))))
  3197.  
  3198. (defcustom custom-mode-hook nil
  3199.   "Hook called when entering custom-mode."
  3200.   :type 'hook
  3201.   :group 'custom-buffer )
  3202.  
  3203. (defun custom-state-buffer-message (widget)
  3204.   (if (eq (widget-get (widget-get widget :parent) :custom-state) 'modified)
  3205.       (message
  3206.        "To install your edits, invoke [State] and choose the Set operation")))
  3207.  
  3208. (defun custom-mode ()
  3209.   "Major mode for editing customization buffers.
  3210.  
  3211. The following commands are available:
  3212.  
  3213. Move to next button or editable field.     \\[widget-forward]
  3214. Move to previous button or editable field. \\[widget-backward]
  3215. \\<widget-field-keymap>\
  3216. Complete content of editable text field.   \\[widget-complete]
  3217. \\<custom-mode-map>\
  3218. Invoke button under the mouse pointer.     \\[Custom-move-and-invoke]
  3219. Invoke button under point.           \\[widget-button-press]
  3220. Set all modifications.               \\[Custom-set]
  3221. Make all modifications default.           \\[Custom-save]
  3222. Reset all modified options.            \\[Custom-reset-current]
  3223. Reset all modified or set options.       \\[Custom-reset-saved]
  3224. Reset all options.               \\[Custom-reset-standard]
  3225.  
  3226. Entry to this mode calls the value of `custom-mode-hook'
  3227. if that value is non-nil."
  3228.   (kill-all-local-variables)
  3229.   (setq major-mode 'custom-mode
  3230.     mode-name "Custom")
  3231.   (use-local-map custom-mode-map)
  3232.   (easy-menu-add Custom-mode-menu)
  3233.   (make-local-variable 'custom-options)
  3234.   (make-local-variable 'widget-documentation-face)
  3235.   (setq widget-documentation-face 'custom-documentation-face)
  3236.   (make-local-variable 'widget-button-face)
  3237.   (setq widget-button-face 'custom-button-face)
  3238.   (make-local-hook 'widget-edit-functions)
  3239.   (add-hook 'widget-edit-functions 'custom-state-buffer-message nil t)
  3240.   (run-hooks 'custom-mode-hook))
  3241.  
  3242.  
  3243. ;;; The End.
  3244.  
  3245. (provide 'cus-edit)
  3246.  
  3247. ;; cus-edit.el ends here
  3248.